T09 · Insecure Skill Coding Practices
- Location
scripts/crypto.sh:176- Finding
Portfolio and Alert Data Stored with Unrestricted Default Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/crypto.sh, lines 176-206 and 256-278
Vulnerability Type: Insecure local storage of sensitive financial data
Risk Level: MediumVulnerable Code
Portfolio storage:
python DATA_DIR = os.path.expanduser("~/.crypto-tracker") PF = os.path.join(DATA_DIR, "portfolio.json") if not os.path.isdir(DATA_DIR): os.makedirs(DATA_DIR) if not os.path.isfile(PF): with open(PF, "w") as f: json.dump([], f) with open(PF) as f: portfolio = json.load(f) sub = os.environ.get("_PF_SUB", "list") args = os.environ.get("_PF_ARGS", "").split() if sub == "add": if len(args) < 3: print("Usage: crypto.sh portfolio add COIN AMOUNT BUY_PRICE") sys.exit(1) coin, amt, price = args[0].upper(), float(args[1]), float(args[2]) portfolio.append({"coin": coin, "amount": amt, "buy_price": price}) with open(PF, "w") as f: json.dump(portfolio, f, indent=2) print("Added: {} x {} @ ${}".format(coin, amt, price)) elif sub == "remove": coin = " ".join(args).strip().upper() before = len(portfolio) portfolio = [p for p in portfolio if p["coin"] != coin] with open(PF, "w") as f: json.dump(portfolio, f, indent=2)Alert storage:
python DATA_DIR = os.path.expanduser("~/.crypto-tracker") AF = os.path.join(DATA_DIR, "alerts.json") if not os.path.isdir(DATA_DIR): os.makedirs(DATA_DIR) if not os.path.isfile(AF): with open(AF, "w") as f: json.dump([], f) with open(AF) as f: alerts = json.load(f) sub = os.environ.get("_AL_SUB", "list") args = os.environ.get("_AL_ARGS", "").split() if sub == "add": if len(args) < 3: print("Usage: crypto.sh alert add BTC above 70000") sys.exit(1) coin, direction, target = args[0].upper(), args[1], float(args[2]) alerts.append({"coin": coin, "direction": direction, "target": target}) with open(AF, ...[truncated 2314 chars]- Remediation
View remediation
Remediation Suggestions
-
Create the data directory with mode
0700and explicitly enforce that mode on existing directories:python os.makedirs(DATA_DIR, mode=0o700, exist_ok=True) os.chmod(DATA_DIR, 0o700) -
Create portfolio and alert files with mode
0600, using low-level flags that prevent following symbolic links where supported:python flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(PF, flags, 0o600) -
Validate existing targets with
os.lstat()and reject symbolic links or non-regular files before reading or writing. -
Correct permissions on existing files with
os.chmod(path, 0o600). -
Write updates to a restricted temporary file in the same directory, flush and synchronize it, and then use
os.replace()for atomic replacement. -
Consider storing only the minimum information required and clearly document that portfolio and alert information is persisted locally.
-
