Back to skill

Security audit

Stock Market Analyzer

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent A-share stock-analysis skill, but its code exposes under-scoped local file access through caller-controlled CSV paths.

Review this before installing. It appears intended for A-share stock analysis, but it should validate stock symbols, avoid caller-controlled filesystem paths, use secure temporary files, clean up outputs, and pin dependencies before use in any environment containing sensitive local files.

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/stock_analyzer.py:26
Finding

Unrestricted File Access and Unsafe Predictable Temporary Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/stock_analyzer.py:26-45, scripts/stock_analyzer.py:59-78, scripts/stock_analyzer.py:92-111, and scripts/stock_analyzer.py:125-148
Vulnerability Type: Path traversal, unrestricted caller-controlled file access, and unsafe temporary-file handling
Risk Level: Medium

Vulnerable Code

python
# query_realtime_price
if time is None:
    time = datetime.now().strftime("%Y-%m-%d %H:%M:%00")

if file_path is None:
    file_path = f"/tmp/{ticker.replace('.', '_')}_realtime.csv"

result = kimi_finance(
    ticker=ticker,
    time=time,
    type="realtime_price",
    file_path=file_path
)

# Read the CSV file and return as dict
if os.path.exists(file_path):
    df = pd.read_csv(file_path)
    if not df.empty:
        return df.to_dict('records')[0]
python
# query_technical_indicators
if time is None:
    time = datetime.now().strftime("%Y-%m-%d %H:%M:%00")

if file_path is None:
    file_path = f"/tmp/{ticker.replace('.', '_')}_tech.csv"

result = kimi_finance(
    ticker=ticker,
    time=time,
    type="realtime_tech",
    file_path=file_path
)

# Read the CSV file and return as dict
if os.path.exists(file_path):
    df = pd.read_csv(file_path)
    if not df.empty:
        return df.to_dict('records')[0]
python
# query_open_summary
if time is None:
    time = datetime.now().strftime("%Y-%m-%d 09:30:00")

if file_path is None:
    file_path = f"/tmp/{ticker.replace('.', '_')}_open.csv"

result = kimi_finance(
    ticker=ticker,
    time=time,
    type="open_summary",
    file_path=file_path
)

# Read the CSV file and return as dict
if os.path.exists(file_path):
    df = pd.read_csv(file_path)
    if not df.empty:
        return df.to_dict('records')[0]
python
# query_close_summary
if time is None:
    time = datetime.now().strftime("%Y-%m-%d 15:00:00")


...[truncated 3251 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate stock symbols with a strict allowlist before using them:

    python
    import re
    
    TICKER_RE = re.compile(r"^\d{6}\.(SH|SZ)$")
    
    def validate_ticker(ticker: str) -> str:
        if not TICKER_RE.fullmatch(ticker):
            raise ValueError("Invalid A-share ticker")
        return ticker
    
  2. Do not expose unrestricted filesystem paths through the public API. Prefer accepting only a filename or generating the destination internally.

  3. Create a private temporary directory and securely generated output file:

    python
    from pathlib import Path
    import tempfile
    
    output_dir = Path(tempfile.mkdtemp(prefix="stock-analyzer-"))
    output_path = output_dir / "result.csv"
    
  4. If caller-selected filenames are required, resolve the path and verify containment in a dedicated approved directory:

    python
    from pathlib import Path
    
    BASE_DIR = Path("/var/tmp/stock-analyzer").resolve()
    
    def safe_output_path(filename: str) -> Path:
        if Path(filename).name != filename:
            raise ValueError("Directory components are not allowed")
    
        destination = (BASE_DIR / filename).resolve()
        if destination.parent != BASE_DIR:
            raise ValueError("Output path escapes the approved directory")
        return destination
    
  5. Reject absolute paths, .. components, path separators, unexpected extensions, and symbolic-link destinations. Open files with exclusive-creation and no-follow semantics where supported.

  6. Avoid predictable shared /tmp filenames. Ensure temporary files and directories are accessible only to the current process user and remove them after parsing.

  7. Validate that the resulting file is a regular file owned by the expected user before reading it. Apply file-size and CSV schema limits to prevent resource exhaustion or unintended data exposure.

  8. Add tests covering absolute paths, traversal seque ...[truncated 94 chars]

Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill description is broad enough to activate on generic finance or stock-related requests, which can cause the agent to invoke this skill when the user did not specifically request A-share analysis. Over-broad routing increases the chance of inappropriate tool use, irrelevant data handling, or bypass of more suitable domain-specific workflows.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill documentation is written predominantly in Chinese and does not provide an English alternative or indicate that the language choice is optional. This creates a natural-language locale constraint that may violate language policy when no user opt-in or justification is given.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The dependency is specified with only a minimum version, which allows future installs to resolve to different releases over time. This weakens supply-chain control and reproducibility, and can lead to accidental installation of vulnerable or incompatible versions if upstream packages are compromised or regress.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pandas>=1.5.0
requests>=2.28.0
numpy>=1.21.0

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
76% confidence
Finding

Pandas has known advisories, and because the manifest does not pin a version, it is impossible to verify whether deployed environments will use an affected release. The risk here is uncertainty in the supply chain rather than proof of a current exploitable state in this file.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using requests>=2.28.0 leaves the final installed version unconstrained above the minimum, so builds are not reproducible and may silently pick up a vulnerable or behavior-changing release. Because requests is a network-facing library, version drift can have security consequences if a newly resolved release introduces or retains a flaw.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
pandas>=1.5.0
requests>=2.28.0
numpy>=1.21.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding

Requests has multiple published advisories, and the absence of an exact version means installations may resolve to an affected release without visibility. Given that this skill likely performs outbound HTTP requests for real-time stock data, a vulnerable requests version is more relevant here than in an offline-only tool.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The unpinned numpy dependency permits uncontrolled upgrades beyond the stated minimum version. This creates supply-chain and reproducibility risk because environments may install different builds, including versions later found vulnerable or unstable.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
pandas>=1.5.0
requests>=2.28.0
numpy>=1.21.0

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
78% confidence
Finding

NumPy has known advisories, but the manifest does not identify the exact installed version, so affectedness cannot be determined. This is a genuine dependency hygiene issue, though the skill context suggests NumPy is likely used for local numerical analysis rather than direct exposure to hostile input.

Content

No source excerpt is available for this finding.