Back to skill

Security audit

A Stock Analysis Litiao

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent A-share stock analysis and local portfolio tracker, with some privacy and deletion caveats users should understand.

Before using portfolio commands, understand that your stock codes, costs, quantities, and timestamps will be saved locally at ~/.clawdbot/skills/a-stock-analysis/portfolio.json. Use remove carefully because it updates that saved file immediately, and consider tightening file permissions if you share the machine with other local users.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/portfolio.py:45
Finding
Portfolio Data Stored Without Explicit Owner-Only Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/portfolio.py`, lines 45–49 **Vulnerability Type**: Plaintext sensitive-data storage with insufficiently enforced file permissions **Risk Level**: Medium ### Vulnerable Code ```python def save_portfolio(data: dict): """保存持仓数据""" PORTFOLIO_FILE.parent.mkdir(parents=True, exist_ok=True) data["updated_at"] = datetime.now().isoformat() with open(PORTFOLIO_FILE, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The portfolio file contains financially sensitive information, including stock codes, purchase costs, quantities, and timestamps. The code creates its parent directories and writes the file using process-default permissions. It does not explicitly require owner-only directory permissions such as `0700` or file permissions such as `0600`. When the file is first created, its permissions are determined by the operating system defaults and the process umask. With a common umask of `022`, the file may be created as `0644`, allowing other local users to read it. The parent directories may similarly be accessible. Reopening an existing file with `open(..., "w")` truncates it but does not correct previously insecure permissions. The portfolio is stored in plaintext at: ```text ~/.clawdbot/skills/a-stock-analysis/portfolio.json ``` No remote exposure is demonstrated. Exploitation requires another local account or process capable of traversing the relevant home-directory path and reading the resulting file. ### Attack Path 1. A user runs a portfolio command such as `add`, `update`, or `analyze`. 2. The command invokes `save_portfolio()`. 3. Python creates or rewrites `portfolio.json` without explicitly enforcing owner-only permissions. 4. Under a permissive umask or pre-existing insecure permissions, the file remains readable by other local users. 5. A local attacker traverses the portfolio directory and reads the JSON ...[truncated 606 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the portfolio directory with owner-only permissions: ```python PORTFOLIO_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700) PORTFOLIO_FILE.parent.chmod(0o700) ``` 2. Create replacement files with mode `0600` and write them atomically: ```python import os import tempfile def save_portfolio(data: dict): PORTFOLIO_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700) PORTFOLIO_FILE.parent.chmod(0o700) data["updated_at"] = datetime.now().isoformat() fd, temporary_path = tempfile.mkstemp( dir=PORTFOLIO_FILE.parent, prefix=".portfolio-", suffix=".tmp", ) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) f.flush() os.fsync(f.fileno()) os.replace(temporary_path, PORTFOLIO_FILE) PORTFOLIO_FILE.chmod(0o600) except Exception: try: os.unlink(temporary_path) except FileNotFoundError: pass raise ``` 3. Correct permissions on existing installations by applying `0700` to the portfolio directory and `0600` to `portfolio.json`. 4. Avoid relying solely on the process umask for sensitive files. 5. If the local threat model includes privileged processes, account compromise, or untrusted backup storage, consider encrypting portfolio data using an operating-system credential store or a user-controlled encryption key. ]]>
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
Findings (4)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly documents state-changing portfolio commands (add, update, remove) but does not warn users that these operations persistently modify local data in `~/.clawdbot/skills/a-stock-analysis/portfolio.json`. In an agent context, missing disclosure and confirmation around local file modification can lead to unintended data changes or loss, especially if the commands are invoked automatically or on behalf of a user.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This Python file contains natural-language descriptions, CLI help text context, and output strings entirely in Chinese, beginning with the module docstring and continuing throughout the script. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present here.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script persists detailed portfolio holdings, including stock codes, quantities, costs, and timestamps, to a predictable file under the user's home directory without any notice, consent flow, or protection controls. In the context of a finance-related skill, this creates a privacy and confidentiality risk because sensitive investment data may be left on disk longer than the user expects and could be exposed to other local users, backups, or compromise of the host.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The remove command deletes a holding from the persisted portfolio file immediately once invoked. While the function prints a message after deletion, it does not warn or confirm the destructive action beforehand, so users are not given a chance to prevent accidental data loss.

Static analysis

No suspicious patterns detected.