Back to skill

Security audit

Skills of A-share announcement data released by ft.tech.

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to fetch the advertised stock announcement and research report data, but its local command dispatcher and PDF saving behavior are broader than they need to be.

Review before installing. Use only the documented subskill names, avoid untrusted output filenames, and do not run it in a directory or installation where overwriting skill files or following symlinks could affect important local files. The observed issues look like insecure scoping and file-handling weaknesses, not proven malicious intent.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
run.py:34
Finding

Unrestricted Handler Path Selection Enables Arbitrary Python Execution

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sub-skills/stock-announcements-specific-url-hash/scripts/handler.py:13
Finding

Symlink-Following Announcement Download Permits Arbitrary File Overwrite

Content
View full analysis
str: """将 output 规范为绝对路径,并限制在 base_dir 内,防止路径遍历。""" base_dir = (base_dir or os.getcwd()).rstrip(os.sep) base_abs = os.path.abspath(base_dir) resolved = os.path.abspath(os.path.normpath(path)) if os.path.commonpath([base_abs, resolved]) != base_abs: print( json.dumps({"error": "output path must be under base directory", "base": base_abs}, ensure_ascii=False), file=sys.stderr, ) sys.exit(1) return resolved ``` ```python raw_output = args.output or f"{args.url_hash}.pdf" output = _safe_output_path(raw_output) url = f"{BASE_URL}/data/api/v1/market/data/announcements/stock-announcements/{args.url_hash}" try: with urllib.request.urlopen(url) as resp: content_type = resp.headers.get("Content-Type", "") data = resp.read() if b"{" in data[:10]: try: err = json.loads(data.decode()) print(json.dumps(err, ensure_ascii=False, indent=2), file=sys.stderr) sys.exit(1) except Exception: pass with open(output, "wb") as f: f.write(data) ``` ### Technical Analysis The `_safe_output_path()` function performs lexical normalization and verifies that the apparent output path is beneath the current working directory. This blocks ordinary `../` traversal but does not resolve or reject symbolic links. Python's `open(output, "wb")` follows a pre-existing symbolic link. Therefore, an output path that appears to be inside the permitted directory can reference a target outside that directory. Opening the target in `wb` mode truncates it before writing the downloaded response. There is ...[truncated 1329 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sub-skills/stock-reports-specific-url-hash/scripts/handler.py:13
Finding

Symlink-Following Report Download Permits Arbitrary File Overwrite

Content
View full analysis
str: """将 output 规范为绝对路径,并限制在 base_dir 内,防止路径遍历。""" base_dir = (base_dir or os.getcwd()).rstrip(os.sep) base_abs = os.path.abspath(base_dir) resolved = os.path.abspath(os.path.normpath(path)) if os.path.commonpath([base_abs, resolved]) != base_abs: print( json.dumps({"error": "output path must be under base directory", "base": base_abs}, ensure_ascii=False), file=sys.stderr, ) sys.exit(1) return resolved ``` ```python raw_output = args.output or f"{args.url_hash}.pdf" output = _safe_output_path(raw_output) url = f"{BASE_URL}/data/api/v1/market/data/report/stock-reports/{args.url_hash}" try: with urllib.request.urlopen(url) as resp: data = resp.read() if b"{" in data[:10]: try: err = json.loads(data.decode()) print(json.dumps(err, ensure_ascii=False, indent=2), file=sys.stderr) sys.exit(1) except Exception: pass with open(output, "wb") as f: f.write(data) ``` ### Technical Analysis The report download handler uses lexical path containment as its only output-path control. Although `abspath()`, `normpath()`, and `commonpath()` prevent basic traversal, they do not prevent the final path or one of its parent components from being a symbolic link. The subsequent `open(output, "wb")` operation follows symbolic links and truncates the resolved target. An attacker with write access to the output directory can consequently redirect the report download into an arbitrary file writable by the Skill process. The separation between path validation and file opening also creates a time ...[truncated 1154 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 18)May include surrounding context.

md
`run.py` 与本文件(`SKILL.md`)位于同一目录。执行时:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises and operationalizes shell execution, file access, and network access via python <RUN_PY> ... and PDF download flows, but it does not declare any explicit tool/permission scope. That creates a governance gap: an orchestrator or reviewer cannot easily constrain what the skill is allowed to do, increasing the risk of unintended command execution, network retrieval, or file operations beyond the user’s expectation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · run.py (reported line 41)May include surrounding context.

python
print(f"错误:未找到 subskill '{subskill}',路径不存在:{handler}", file=sys.stderr)
        sys.exit(1)

    result = subprocess.run(
        [sys.executable, handler] + sys.argv[2:],
        cwd=SKILL_ROOT,
    )

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language strings in the module docstring and CLI descriptions are exclusively in Chinese, with no indication that the user can choose another language or that the skill is intentionally restricted to a Chinese-speaking audience. Under the stated policy, forcing a specific language without opt-in is a locale/language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file's docstring and command-line descriptions are entirely in Chinese, which imposes a specific language on users without any visible opt-in or explanation of a region-specific requirement. Under the language/locale policy, forcing a specific language without user choice can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code includes user-facing natural-language strings entirely in Chinese, including the module docstring, command description, and argument help text. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The skill instructs downloading and saving PDFs with an --output filename but provides no warning or safeguard around local file creation, overwrite behavior, or path handling. In practice, this can lead to accidental overwriting of existing files or writing to unintended locations if the output parameter is not constrained by the implementation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring and runtime usage/error messages are presented only in Chinese, which imposes a specific language on users without any visible opt-in or alternative. The policy for this audit flags language or locale constraints when they are forced rather than optional or justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file presents the skill name, usage, parameters, and notes entirely in Chinese. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code constructs a URL from the user-provided date and pagination arguments and sends it to a remote service with urllib.request.urlopen. Although the operation is central to the script's purpose, the file itself provides no explicit comment, docstring detail, or user-facing notice that supplied parameters will be transmitted over the network to an external endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code performs an HTTP request to an external domain using the user-supplied stock code as a query parameter. While the network access is central to the script's purpose, there is no explicit user-facing notice, prompt, or comment in this file disclosing that input will be transmitted to a remote service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file presents all user-facing instructions exclusively in Chinese. Under the language/locale policy rule, forcing a single language without opt-in or justification can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file states that the script saves a file to a local path and returns the saved location, but it does not include any user warning about writing to disk or possible overwrite/storage effects. Under the markdown-file criteria for SQP-2, behaviors affecting user data or system state should be disclosed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.