Back to skill

Security audit

Earnings Review Agent

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent stock earnings review integration, but users should understand it sends queries to Eastmoney APIs and saves returned report attachments locally.

Install only if you trust the Eastmoney API service and are comfortable providing EM_API_KEY. Expect the skill to send your query and stock/report identifiers to that service, save returned PDF/Word or spreadsheet attachments under a local miaoxiang/stock-earnings-review run directory, and possibly leave debug logs if debug mode is enabled. Treat generated links and saved attachments as external content.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/common.py:202
Finding

Unbounded and Unvalidated Decoding of Remote Attachment Data

Content
View full analysis

Vulnerability Details

File Location: scripts/common.py, lines 202-208
Vulnerability Type: Unrestricted base64 decoding and unsafe attachment handling
Risk Level: Medium

Vulnerable Code:

python
if isinstance(payload.get("base64"), str):
    b64 = payload["base64"].strip()
    if not b64:
        return None
    raw = base64.b64decode(b64)
    path.write_bytes(raw)
    return str(path)

The decoded data originates from the remote performance-comment API. In scripts/call_review_api.py, API fields are assigned trusted-looking document names such as review.pdf, review.doc, and review_data.xlsx before being passed to this function.

Technical Analysis

The implementation decodes the complete remote base64 value into memory without enforcing a maximum encoded or decoded size. Python's default base64.b64decode behavior is also used without validate=True, so malformed or noncanonical input is not rejected strictly.

After decoding, the bytes are written under a document extension without checking file signatures, expected MIME types, or the actual file format. Consequently, a compromised or malfunctioning upstream API could provide an arbitrarily large payload or content that is not a genuine PDF, Word document, or spreadsheet.

HTTP response processing also calls resp.json() before attachment limits are applied, meaning an excessively large JSON response can consume substantial memory even before base64 decoding begins.

Attack Path

  1. An attacker compromises, impersonates through a trusted upstream path, or otherwise controls the performance-comment API response.
  2. The response includes an oversized or disguised value in pdfBase64, wordBase64, or a supported data-sheet field.
  3. call_review_api.py loads the response and forwards the base64 value to save_attachment_payload.
  4. The complete payload is decoded into memory without a size limit.
  5. The resulting byt ...[truncated 878 chars]
Remediation
View remediation

Remediation Suggestions

  • Enforce a strict maximum HTTP response size before parsing the complete response body.

  • Reject encoded attachment values above a configured limit and calculate the maximum possible decoded size before decoding.

  • Use strict decoding:

    python
    raw = base64.b64decode(b64, validate=True)
    
  • Stream large attachments where the API permits it rather than materializing the entire decoded file in memory.

  • Validate file signatures and structure against the expected output type:

    • PDF: %PDF-
    • Modern Office documents: ZIP container signature plus expected internal entries
    • Legacy Word documents: expected Compound File Binary signature
  • Reject content whose detected type does not match the intended extension.

  • Write through a temporary file in the destination directory and atomically rename it only after validation succeeds.

  • Set restrictive file permissions and enforce per-run storage quotas.

  • Handle decoding, validation, and disk-space errors explicitly without leaving partial files behind.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/call_review_api.py:75
Finding

Untrusted Remote Content and Share URLs Are Returned Without Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/call_review_api.py, lines 75-82
Vulnerability Type: Unsanitized remote content propagation
Risk Level: Medium

Vulnerable Code:

python
result = {
    "title": title,
    "content": content,
    "shareUrl": parsed.get("shareUrl"),
    "files": {
        "pdf": saved_attachments.get("pdfBase64"),
        "word": saved_attachments.get("wordBase64"),
        "dataSheet": saved_attachments.get("dataSheetBase64"),
    },
}

The orchestration instructions explicitly direct the agent to use these remote values in its final response:

markdown
- **正文**:直接基于接口返回的 `content` 文本进行整理后输出。
- **分享链接**:接口返回的 `shareUrl`。

Technical Analysis

The title, content, and shareUrl fields originate from a remote API response and are returned without trust-boundary enforcement. The code does not validate the URL scheme or hostname, sanitize active Markdown or HTML, or identify remote response text as untrusted data that must not be interpreted as agent instructions.

If the upstream response is compromised, content could contain deceptive Markdown, hostile instructions, or links to attacker-controlled resources. Likewise, shareUrl could use an unexpected scheme or direct the user to an unrelated phishing or malware-delivery domain.

This is not evidence that the current Skill contains an embedded instruction-hijacking payload. It is an insecure data-handling boundary that could allow a future malicious upstream response to affect user-visible output.

Attack Path

  1. An attacker gains control over, or injects content into, the upstream performance-comment response.
  2. The attacker supplies crafted Markdown or instruction-like text in content, and optionally an attacker-controlled value in shareUrl.
  3. extract_comment_response_fields extracts the values without validation.
  4. call_review_api.py returns the values unchanged in ...[truncated 879 chars]
Remediation
View remediation

Remediation Suggestions

  • Treat all API response text as untrusted data, not as instructions to the agent.
  • Establish an explicit orchestration boundary stating that text inside title and content must only be summarized or quoted and must never alter tool use, system behavior, or safety constraints.
  • Sanitize or escape active HTML and unsafe Markdown constructs before rendering.
  • Validate shareUrl with a strict URL parser:
    • Permit only https.
    • Permit only documented East Money share-link hostnames.
    • Reject embedded credentials, malformed ports, control characters, and unexpected redirects.
  • Display the validated destination hostname to the user.
  • If a URL fails validation, omit it and return a clear validation warning.
  • Consider returning structured report sections instead of unrestricted markup where supported by the API.

T08 · Insecure Dependencies

Note
Location
SKILL.md:14
Finding

Unpinned Third-Party Dependency Installation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 14-20
Vulnerability Type: Unpinned runtime dependency
Risk Level: Low

Vulnerable Code:

json
"install": [
  {
    "id": "pip-deps",
    "kind": "python",
    "package": "httpx",
    "label": "Install Python dependencies"
  }
]

The documented manual installation command is similarly unpinned:

bash
pip3 install httpx --user

Technical Analysis

The Skill requests installation of httpx without a reviewed version constraint, lockfile, or package hash. Installation therefore resolves whichever compatible release and transitive dependencies are available from the configured package index at installation time.

The dependency name itself is legitimate and there is no evidence in the audited project of typosquatting, dependency confusion, or a currently malicious package. Nevertheless, the absence of version and integrity controls makes installations non-reproducible and expands exposure to future compromised, vulnerable, or incompatible releases.

Installing with --user also affects the invoking user's Python environment rather than an isolated environment, increasing the scope of dependency conflicts.

Attack Path

  1. A future release of httpx or one of its transitive dependencies becomes compromised, malicious, or materially vulnerable, or the configured package index is compromised.
  2. A user installs the Skill dependency using the unpinned package declaration or documented command.
  3. The package manager resolves the affected release because no version or hash restriction prevents it.
  4. Package installation hooks or imported dependency code execute with the privileges of the user running the installation or Skill.
  5. Any resulting compromise is bounded by that user's permissions but may affect other Python applications sharing the user-level environment.

Impact Assessment

No current compromise wa ...[truncated 455 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin httpx to a reviewed exact version rather than resolving the latest release.
  • Maintain a lockfile containing reviewed transitive versions.
  • Use package hashes, such as pip's --require-hashes, to verify artifact integrity.
  • Install from an explicitly configured trusted index.
  • Use a project-specific virtual environment instead of pip install --user.
  • Add automated dependency vulnerability and provenance checks.
  • Establish a controlled update process that reviews and tests dependency changes before changing the lockfile.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

该代码块的核心行为是:向 REPORT_LIST_API 发送请求,基于 entity.em_code 获取 reportDateList,解析成候选报告期列表,然后根据 selected_report_date 做严格或非严格匹配,最终输出实体信息、可选报告期和匹配结果。这属于报告期标准化/预处理组件。声明中的主要用途则是对公司财报和业绩进行分析解读并生成点评内容。两者在主要目的和对外能力上存在明显差异。虽然获取报告期可能是后续财报分析流程的支持步骤,但当前代码本身并未实现描述中承诺的核心能力,因此应判定为描述与实际行为不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill requires environment access, network calls, and local file writes, but it does not declare an explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and can let the skill operate with broader capabilities than reviewers or orchestrators expect, especially since it also saves attachments and debug artifacts to disk.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

L007 规定“即使用户未明说‘业绩点评’,只要意图是对该公司财报或业绩作分析解读,也应触发”,这是一个基于宽泛意图判断的触发条件,没有给出排除条件或负例。该表述容易与一般性的公司分析、投资讨论或新闻解读重叠,增加非预期调用此 skill 的风险。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill states it will save attachments locally and may persist debug logs, but it does not present a clear user-facing consent/retention notice despite potentially storing financial-analysis artifacts and raw API responses on disk. In shared or persistent environments, this can expose sensitive user queries, generated documents, or metadata to other users or later sessions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code automatically decodes and writes API-provided attachments to local disk whenever an attachment directory or log path is available, including a fallback path even when the caller did not explicitly request attachment persistence. This creates an unintended file-write side effect, which can expose sensitive report contents, leave residual files on shared systems, and store untrusted files from a remote service without clear user consent or strong controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The helper writes arbitrary JSON data to a file in the run log directory, which affects local user data and filesystem state. The file contains no confirmation prompt or user-visible notice around this write behavior, and the surrounding comments/docstrings are developer-oriented rather than a user disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code decodes attachment payloads and writes them to a local path, which is a safety-relevant file write operation. Although there are docstrings describing the function for developers, there is no confirmation prompt, user-facing log/print, or other disclosure to the user in this file that attachments will be persisted locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code constructs authenticated headers and posts the user-provided query to an external API, which transmits user data and likely credential material off-process. There is no confirmation prompt, logging/print statement, or explanatory comment/docstring in this file warning that the query will be sent over the network with authentication headers.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

L183-L187 对响应中的数学公式格式作了强制性要求,且整个技能描述均以中文规定输出行为,但未说明这是用户可选项或特定区域/组织规范的一部分。若该 skill 面向多语言用户或跨区域环境,固定语言/格式约束可能构成未获用户选择的语言/locale 策略限制。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The raised RuntimeError messages are hard-coded in Chinese, which imposes a specific language choice on users regardless of their locale or preferences. The file does not offer language selection or document a justified locale restriction.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.