Back to skill

Security audit

stock-portfolio-advisor

Security checks for vulnerabilities and agentic risk

Overview

The skill fits a stock-analysis use case, but it should be reviewed because it auto-runs an external npm data tool and has a local snapshot-write bug that could overwrite portfolio JSON files.

Install only if you trust the npm data client and its registry path, and consider running the skill in a restricted workspace. Do not run snapshot commands on untrusted result JSON until the date field is strictly validated as `YYYY-MM-DD` and constrained to the history directory.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:47
Finding
Automatic Retrieval and Execution of a Third-Party npm Package## Vulnerability Details **File Location**: `SKILL.md:47, 70-74`; `references/data-playbook.md:7, 18, 23-28, 44-67` **Vulnerability Type**: Unsafe third-party dependency retrieval and execution **Risk Level**: Medium ### Vulnerable Code ```text Main access channels are the connected westock-mcp and: npx -y westock-data-skillhub@1.0.5 ``` ```powershell npx -y westock-data-skillhub@1.0.5 quote sh600519,sz000725 npx -y westock-data-skillhub@1.0.5 kline sh600519,sz000725 --period day --limit 250 npx -y westock-data-skillhub@1.0.5 finance sh600519,sz000725 --num 8 npx -y westock-data-skillhub@1.0.5 risk sh600519,sz000725 npx -y westock-data-skillhub@1.0.5 consensus sh600519,sz000725 ``` The data playbook also establishes this command as the primary bulk-data channel: ```bash WD="npx -y westock-data-skillhub@1.0.5" $WD market-overview $WD quote $CODES $WD finance $CODES --num 8 $WD risk $CODES ``` ### Technical Analysis The Skill directs the Agent to invoke `npx` with the `-y` option. If the package is not already available locally, `npx` can retrieve it from the configured npm registry and execute its entry point without an interactive installation confirmation. Pinning the package to version `1.0.5` limits ordinary version drift, but the project does not provide or verify an npm integrity digest, lockfile, vendored artifact, trusted registry policy, or independently reviewed copy. Consequently, the effective executable payload is determined by an external package registry at execution time rather than solely by the audited repository. This creates a supply-chain execution boundary. A compromise of the named npm package, its publisher account, the configured registry, or the dependency graph used during package resolution could result in arbitrary code being run with the same operating-system privileges as the Agent. ### Attack Path 1. An attacker compromises the npm publisher account, registry distribution path, or a package dependency associated with `w ...[truncated 1102 chars]
Remediation
## Remediation Suggestions 1. Vendor a reviewed release of the data client into a controlled distribution channel rather than downloading it during each workflow. 2. Verify the package tarball against a pinned SHA-256 or npm integrity value before execution. 3. Use a committed lockfile and an installation mode that enforces exact dependency integrity. 4. Prefer a trusted internal registry or allowlisted artifact repository. 5. Remove automatic `-y` execution from the default workflow and require explicit user approval before the first external package installation. 6. Run the data client in a sandbox with no access to unrelated files, credentials, or sensitive environment variables. 7. Restrict outbound network access to the specific market-data endpoints required by the client. 8. Document the package publisher, provenance, expected integrity value, and dependency-review process.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/portfolio_ledger.py:141
Finding
Path Traversal Through an Unvalidated Snapshot Date## Vulnerability Details **File Location**: `scripts/portfolio_ledger.py:141-145` **Vulnerability Type**: Path traversal and arbitrary JSON file overwrite **Risk Level**: Medium ### Vulnerable Code ```python def cmd_snapshot(args): d = ledger_dir(args.dir) result = json.loads(Path(args.result).read_text(encoding="utf-8")) date = args.date or result.get("date") or datetime.now().strftime("%Y-%m-%d") target = d / "history" / f"{date}.json" result["date"] = date target.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8") print(f"[OK] 快照已保存: {target}") return 0 ``` ### Technical Analysis The snapshot filename is derived from either the `--date` argument or the `date` property of the supplied result JSON. Despite being documented as a date, the value is not parsed or validated as `YYYY-MM-DD`. `pathlib` treats embedded path separators and parent-directory components as path syntax. Therefore, a value such as `../positions` causes: ```python d / "history" / "../positions.json" ``` to refer effectively to `d/positions.json`, outside the intended `history` directory. The use of `write_text()` then overwrites the destination if it already exists. The issue can be triggered through an explicit CLI argument or through an attacker-controlled result JSON file. No canonical-path containment check ensures that the final path remains beneath the history directory. ### Attack Path 1. An attacker supplies or influences a scoring result JSON file with a malicious date value: ```json { "date": "../positions", "stocks": [] } ``` 2. The Agent runs the documented snapshot command: ```bash python scripts/portfolio_ledger.py snapshot \ --result attacker-result.json \ --dir workspace/portfolio_ledger ``` 3. `cmd_snapshot()` reads `../positions` from the result. 4. It constructs `workspace/portfolio_ledger/history/../positions.json`. 5. The operating system resolves the parent-directory component to `workspac ...[truncated 935 chars]
Remediation
## Remediation Suggestions 1. Parse and validate the value as a strict calendar date: ```python from datetime import datetime raw_date = args.date or result.get("date") or datetime.now().strftime("%Y-%m-%d") snapshot_date = datetime.strptime(raw_date, "%Y-%m-%d").date().isoformat() ``` 2. Explicitly reject `/`, `\`, `..`, absolute paths, NUL characters, and values outside the expected date format. 3. Canonicalize the destination and enforce directory containment: ```python history_dir = (d / "history").resolve() target = (history_dir / f"{snapshot_date}.json").resolve() if target.parent != history_dir: raise ValueError("Snapshot path escapes the history directory") ``` 4. Use the validated ISO date rather than the raw input when updating `result["date"]`. 5. Use an atomic write operation to avoid partial snapshots. 6. Define an explicit overwrite policy. If replacing an existing date is not intended, create the file with exclusive mode and require a separate `--replace` option. 7. Add regression tests covering `../positions`, absolute paths, encoded separators, Windows separators, invalid dates, and valid leap-day dates.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

Static analysis

No suspicious patterns detected.