Back to skill

Security audit

Stock Analysis CN

Security checks for vulnerabilities and agentic risk

Overview

The skill has no hidden backdoor, but it can generate investment recommendations from mock or placeholder data and uses unsafe local file-writing/cache behavior.

Install only for experimentation or code review. Do not rely on its investment recommendations without fixing the mock data paths, scoring calculation, ticker validation, output-path restrictions, and cache safety; never provide browser session cookies to it.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils.py:16
Finding

Predictable Shared Cache Permits Symlink Following and Path Traversal

Content
View full analysis

Vulnerability Details

File Location: scripts/utils.py, lines 16-22, 44-55, and 122
Vulnerability Type: Unsafe temporary-file and path construction
Risk Level: High

Vulnerable Code

python
# Cache directory
CACHE_DIR = Path("/tmp/stock_analysis_cache")
CACHE_DIR.mkdir(exist_ok=True)


def cache_path(ticker: str, data_type: str, suffix: str = "json") -> Path:
    """Generate cache file path."""
    return CACHE_DIR / f"{ticker}_{data_type}.{suffix}"
python
cache_file = cache_path(ticker, f"kline_{days}")

if is_cache_valid(cache_file):
    try:
        with open(cache_file, 'r') as f:
            return json.load(f)
    except:
        pass  # Cache read failed, fetch fresh

url = f"https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq&param={ticker},day,,,{days},qfq"
try:
    resp = requests.get(url, timeout=10)
python
with open(cache_file, 'w') as f:
    json.dump(result, f, ensure_ascii=False, indent=2)

Technical Analysis

The cache uses a fixed, predictable directory under the globally shared /tmp hierarchy. The directory is created with exist_ok=True, but the code does not verify:

  • Whether an existing path is a real directory rather than a symlink.
  • Whether the directory is owned by the current process user.
  • Whether its permissions prohibit modification by other local users.
  • Whether an individual cache entry is a regular file rather than a symbolic link.

The ticker is also directly incorporated into the cache path without format validation. Path separators and .. components are therefore not rejected, allowing the resolved cache path to escape the intended directory in execution contexts where an attacker controls the ticker.

Ordinary open(..., 'w') follows symbolic links and truncates the target. Consequently, a maliciously prepared cache entry can redirect a successful cache write to another file writable by the Skill process. Cache reads also follow symbolic lin ...[truncated 1932 chars]

Remediation
View remediation

Remediation Suggestions

  1. Strictly validate ticker values before they reach either the URL or filesystem:
python
TICKER_PATTERN = re.compile(r"^(sh|sz)\d{6}$")

def validate_ticker(ticker: str) -> str:
    if not TICKER_PATTERN.fullmatch(ticker):
        raise ValueError("Invalid ticker format")
    return ticker
  1. Validate days as an integer within the supported range, such as 1 through 320.

  2. Use a per-user private cache directory rather than a predictable shared directory. Create it with mode 0700 and verify ownership.

  3. Resolve every generated path and verify that it remains under the resolved cache root:

python
candidate = (CACHE_DIR / filename).resolve()
candidate.relative_to(CACHE_DIR.resolve())
  1. Reject cache paths that are symbolic links or non-regular files.

  2. Open files using operating-system flags that prevent symlink following, such as O_NOFOLLOW where supported.

  3. Write to a securely created temporary file in the same directory, flush and synchronize it, and then atomically replace the destination.

  4. Do not silently accept an attacker-created cache directory. Verify that the directory is owned by the expected user and is not group- or world-writable.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/report_generator.py:202
Finding

Mock Financial Data and Inflated Scoring Produce Misleading Investment Recommendations

Content
View full analysis

Vulnerability Details

File Location: scripts/fundamental_analysis.py, lines 60-76; scripts/valuation_analysis.py, lines 141-148; scripts/report_generator.py, lines 202-204
Vulnerability Type: Financial-output integrity failure
Risk Level: High

Vulnerable Code

The fundamental-analysis path returns fixed test data instead of current financial statements:

python
# For now, return mock data for testing
return {
    'income_stmt': {
        'revenue': 1000000,
        'net_profit': 100000,
        'gross_profit': 300000,
    },
    'balance_sheet': {
        'equity': 500000,
        'assets': 2000000,
        'debt': 800000,
        'current_assets': 400000,
        'current_liabilities': 200000,
    },
    'cash_flow': {
        'operating_cf': 120000,
    }
}

The valuation path assigns fixed values to every unsupported non-bank ticker:

python
else:
    # Generic placeholder for non-bank stocks
    metrics.pe = 25.3
    metrics.pb = 3.2
    metrics.pe_5y_median = 24.1
    metrics.pb_5y_median = 3.0
    metrics.industry_pe_median = 22.5
    metrics.industry_pb_median = 2.8

The report generator then multiplies an already 0-to-10 component-score average by ten:

python
total_score = sum(comp_scores.values()) / len(comp_scores) * 10

recommendation = generate_recommendation(total_score, comp_scores)

Technical Analysis

The Skill presents itself as a data-driven stock-analysis system, but important report fields are derived from static or mock values without a machine-readable indication that the data is synthetic.

The component scores produced by generate_score_components() are already expressed on a 0-to-10 scale. Their arithmetic mean is therefore also on a 0-to-10 scale. Multiplying that average by ten changes the range to 0-to-100, while generate_recommendation() continues to compare it against thresholds intended for a 0-to-10 score.

For example, four neutral component scores of 5.0 produce ...[truncated 2114 chars]

Remediation
View remediation

Remediation Suggestions

  1. Correct the score calculation by removing the additional multiplication:
python
total_score = sum(comp_scores.values()) / len(comp_scores)
  1. Add unit tests covering every recommendation boundary, including scores immediately below, equal to, and above 4.0, 5.0, 6.5, and 8.0.

  2. Remove mock financial statements from production analysis paths. Keep test fixtures in a dedicated test module.

  3. Return an explicit unavailable-data result when real financial data cannot be obtained:

python
{
    "available": False,
    "source": None,
    "reason": "Financial statements are unavailable"
}
  1. Do not generate buy, hold, or sell recommendations when required inputs are unavailable, stale, synthetic, or insufficient.

  2. Attach provenance to every metric, including the source, retrieval time, reporting period, whether the value is estimated, and whether it is static.

  3. Clearly label any benchmark approximation in both structured output and rendered reports. Never present a generic placeholder as the current value for a specific ticker.

  4. Require a minimum data-completeness threshold before calculating a composite score.

  5. Add schema validation so that mock, missing, or stale values cannot silently enter the production recommendation pipeline.

  6. Review the remaining financial calculations for correctness before using the Skill for real investment decisions.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是一个完整的A股投资分析与报告生成工具,但实际代码仅包含一个简单的 main() 函数并打印示例文本,且注释明确表示这是占位脚本、待后续实现。因此代码的实际行为与声明用途存在明显且实质性的不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述的是一个功能完整的A股综合分析与报告生成工具,覆盖技术面、估值、风险、基本面,并能输出Word投资报告。但提供的代码只是 fundamental_analysis.py,且是一个未完成的基本面分析模块。get_financial_statements 明确写明“Currently not implemented”,返回的是 mock data;calculate_metrics 中实际计算逻辑被注释掉,因此大多数指标不会生成;generate_summary 只会在少数指标存在时输出文字,否则返回“数据不足”。代码中没有技术指标计算、风险评估逻辑、行业估值基准实现,也没有Word文档生成功能。数据源层面虽然文档字符串提到腾讯财经API和东方财富API,但实际没有发起任何API请求。综合来看,代码实际行为与声明的主要用途存在明显且实质性的差异。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding

整体上,代码的核心用途与描述较为接近:确实整合了技术面、估值、风险和基本面分析,调用腾讯相关K线获取价格,并生成一份投资分析报告,也包含行业估值基准对比。因此不存在完全不同的主用途。主要不一致在于“自动生成Word投资报告”这一点:代码使用的是 analysis_report.md / analysis_report_simple.md 模板,返回内容也是字符串;即使通过 --output 保存,也只是按文本写出,没有任何生成 .doc/.docx 或 Word 专有格式处理逻辑。另一个较小的不一致是描述强调“A股”,而代码入口和注释写的是 stock/ETF analysis report,示例也为沪深300ETF,说明覆盖范围不止A股个股。不过这属于范围表述偏差,严重性低于Word格式不符。综合判断为存在描述与实际行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述的是一个完整的A股投资分析与报告生成能力集合,包含技术面、估值、风险、基本面及Word报告输出。实际代码只是 risk_analysis.py 单一模块,主要从腾讯财经API获取价格数据并计算风险指标,属于声明中“风险”部分的一个子集。代码没有显示任何技术指标计算、财务基本面处理、行业专用估值基准、Word文档生成或完整报告拼装流程。因此描述显著夸大了该代码块的实际能力,属于明显不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

声明描述的是一个面向A股的全覆盖分析与报告生成能力,而代码片段实际是一个screening模块,核心功能是根据若干因子对股票/ETF候选池进行过滤和打分排序。它没有生成Word文档,也没有实现完整的技术面、风险、基本面综合分析报告。代码中的很多支持因子仅出现在注释或预设权重中,但实际enrich_with_metrics只填充了少量字段:成交量、1/3/6月收益、PE/PB、极少数模拟ROE;诸如ROA、负债率、现金流质量、波动率、beta、最大回撤、营收CAGR等并未真正计算。数据获取方面,Universe主要来自本地CSV文件,腾讯接口只用于K线历史价格,不足以支撑声明中的“基于腾讯财经API全覆盖分析”。因此该代码与声明在主要目的和实际能力上存在明显不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

该代码与声明存在明显不匹配。声明描述的是一个覆盖技术面、估值、风险、基本面的完整A股分析与Word报告生成工具;但提供的代码块仅是 technical_analysis.py,功能集中在拉取腾讯财经K线数据并进行技术指标计算与趋势总结。虽然“基于腾讯财经API”的部分基本吻合,但其余核心承诺——估值、行业估值基准、风险分析、基本面覆盖、Word报告生成——在此代码中均未体现。因此从描述与实际行为对比看,代码实际能力显著少于声明的主要用途。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

声明描述的是一个功能完整的A股一键分析与报告生成技能,但实际代码仅是底层辅助工具的一部分。已实现内容主要是腾讯财经K线抓取、缓存和基础数学工具,这与“基于腾讯财经API”部分部分一致;然而技术面、估值、风险、基本面全覆盖分析和Word报告生成等核心承诺在该代码中并未实现。代码也没有显示任何行业估值基准逻辑。不存在明显额外的未声明敏感能力,但该片段的实际能力明显弱于声明,属于描述与行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的是一个覆盖多维度投资分析并生成Word报告的完整A股分析工具,还特别强调基于腾讯财经API。实际代码只包含 valuation_analysis.py,一个单独的估值分析模块,且实现明显为简化版:历史估值数据函数直接返回空,主要数据来自硬编码银行样例和通用占位值,输出只是字典和文本摘要。虽然“估值分析”这一小部分与声明存在部分重合,但整体主功能范围远小于声明,且关键能力(技术面、基本面、风险、Word报告、腾讯财经API接入)均未体现,因此属于明显的描述与行为不一致。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises capabilities that imply network access and local file read/write, but it does not declare any explicit tool scope or permissions boundary. In an agent environment, undeclared capabilities reduce transparency and policy enforcement, increasing the chance that the skill performs external requests or writes files without the user's informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill describes use of external finance APIs and web scraping but does not clearly warn users that their prompts or requested tickers may trigger third-party network requests. In agent settings, undisclosed outbound retrieval can leak user interest, trading intent, or other sensitive context to external providers and makes data provenance and privacy harder to assess.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The entire report template, including headings, labels, and disclaimer text, is written only in Chinese. This creates a language/locale constraint without any visible opt-in or alternative, which matches the policy concern for forced language output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The template content, section headings, labels, and disclaimer are entirely written in Chinese, which imposes a specific language/locale by default. Under the policy, language constraints should be user-selectable or clearly justified; this file provides neither an opt-in nor a documented region-specific rationale.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document claims the skill does not require personal login, yet it also describes authenticated access to Jisilu via browser automation or a session cookie. This inconsistency can mislead users and implementers into handling authentication material when they may not expect it, increasing the chance of insecure credential collection or use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Suggesting that users provide a session cookie exposes a reusable authentication token that can grant account access and facilitate session hijacking. Even though the text says this is 'not recommended for security,' it still documents the practice as an option without strong prohibition or secure handling requirements.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file gives direct trading implications such as 'Buy near support, sell near resistance' and breakout/breakdown cues without any warning that these are educational heuristics, not reliable investment advice, and that losses can occur. In the context of a skill marketed as one-click A-share analysis that auto-generates investment reports, this omission increases the chance users will over-trust the output and make risky financial decisions.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The function is documented as fetching real financial statements, but it returns hardcoded mock data instead. In an investment-analysis skill, this creates materially misleading outputs that can be mistaken for real analysis and may drive financial decisions based on fabricated data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The main analysis entry point claims to perform full fundamental analysis, but it relies on placeholder inputs and a metrics calculator that leaves most fields unset. In the context of a stock-analysis skill that advertises comprehensive A-share analysis and report generation, this is dangerous because users may trust incomplete or fabricated analysis as investment-grade output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The generated natural-language assessment uses fixed Chinese phrases such as "优秀", "良好", "偏低", and "数据不足" with no option for the user to select language or locale. This is a natural-language policy concern because the skill imposes a specific language in user-facing output rather than offering opt-in or documenting a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains user-facing recommendation text exclusively in Chinese, and similar Chinese-only strings appear throughout the generated report. Because the skill does not provide any user opt-in or language/locale selection, it creates a natural-language locale policy concern under the language-choice requirement.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The CLI accepts an arbitrary --output path and writes the generated report there without any path restrictions or user-safety guardrails. In an agent/skill context, this creates an unintended filesystem side effect that can overwrite local files if an external caller or prompt controls the argument, which exceeds a pure 'analysis/report generation' capability.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The summary strings in generate_summary are written entirely in Chinese, and the file provides no option for users to select or opt into that locale. This can violate language/locale policy when the skill is used in broader contexts where user language preference is not guaranteed.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The top-level documentation lists quality, growth, momentum, low-volatility, and dividend factors such as ROA, Debt/Equity, CF quality, CAGR, beta, and volatility. In practice, enrich_with_metrics only computes volume, short-horizon returns, PE/PB, and a mocked ROE value for two tickers, while other listed factors are absent or explicitly marked as placeholders.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This Python file contains user-facing strings in Chinese, and several function/docstring descriptions also assume a Chinese-language interface. Because the skill does not offer a language choice or explain that it is intentionally region-specific, it creates a locale policy concern under the language/locale rule.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file-level docstring advertises a general 'Screening Module for Stocks and ETFs', but fetch_universe only looks for local ETF list CSV files and forcibly sets instrument_type to 'etf'. That means the default workflow does not actually implement stock-universe discovery despite claiming stock screening capability.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Multiple summary strings and preset descriptions are written only in Chinese, which indicates the skill enforces a single language experience. The file does not expose any mechanism for language selection or document a justified regional limitation.

Content

No source excerpt is available for this finding.