Back to skill

Security audit

Skill Fin Report

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated finance-report purpose, but it needs Review because it can overwrite arbitrary writable files and renders unescaped user or market data into PDFs.

Install only if you are comfortable running a Python finance-data workflow with network access and local PDF generation. Run it as an unprivileged user, preferably in a virtual environment, avoid using --output with arbitrary paths, keep author input plain text, and consider pinning/auditing dependencies before use.

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

Error
Location
scripts/generate_weekly_report.py:78
Finding

Arbitrary File Overwrite Through Unrestricted Output Path

Content
View full analysis
str: """将 HTML 渲染为 PDF,通过 Ghostscript 优化以兼容 macOS Preview""" import subprocess, tempfile, shutil, os tmp_path = output_path + ".tmp.pdf" HTML(string=html_content).write_pdf(tmp_path) gs_bin = shutil.which("gs") if gs_bin: try: subprocess.run([ gs_bin, "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4", "-dPDFSETTINGS=/prepress", "-dEmbedAllFonts=true", "-dSubsetFonts=true", f"-sOutputFile={output_path}", tmp_path, ], check=True, capture_output=True) os.remove(tmp_path) except subprocess.CalledProcessError: os.replace(tmp_path, output_path) else: os.replace(tmp_path, output_ ...[truncated 2298 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/report_generator.py:125
Finding

HTML Injection in PDF Rendering Allows Report Manipulation and Unintended Resource Requests

Content
View full analysis
len(s.sell_signals)) bear = sum(1 for s in signals if len(s.sell_signals) > len(s.buy_signals)) neut = len(signals) - bull - bear items = "" for s in signals: d = "看多" if len(s.buy_signals) > len(s.sell_signals) else "看空" if len(s.sell_signals) > len(s.buy_signals) else "中性" items += f'
  • {s.name}({s.symbol}):{d},信号{s.signal_strength},风险{s.risk_score:.1f}/10,仓位{s.position_coeff:.0%}
  • \n' return f"""
    AI 投研助手 证券研究报告 · 每周技术分析
    每周金融投研报告
    报告周期:{start} 至 {end}
    发布日期:{report_date}    分析师:{author}    数据来源:AKShare / 新浪财经 / 东方财富
    """ ``` Stock news and macro headlines are also inserted without escaping: ```python for symbol, news_list in stock_news.items(): sname = name_map.get(symbol, symbol) for n in news_list[:3]: title = n.get("title", "")[:60] time_str = n.get("time", "")[:10] items += f'
  • {sname}:{title} ({time_str})
  • \n' ``` ```python if headlines: macro_items = "" for h in headlines[:4]: text = h[:70] + "…" if len(h) > 70 else h macro_items += f"
  • {text}
  • \n" ``` The author value is interpolated again i ...[truncated 3792 chars]
    Remediation
    View remediation

    T08 · Insecure Dependencies

    Warning
    Location
    requirements.txt:1
    Finding

    Unpinned Executable Dependencies Create Supply-Chain and Reproducibility Risk

    Content
    View full analysis
    =1.10.0 pandas>=1.5.0 numpy>=1.23.0 weasyprint>=60.0 matplotlib>=3.7.0 ``` The documented setup installs those unconstrained future versions: ```bash pip3 install -r {baseDir}/requirements.txt python3 {baseDir}/scripts/generate_weekly_report.py --stocks 000001,600519,000858 --skip-breadth ``` ### Technical Analysis Every dependency is specified only with a minimum version. Any future release satisfying the lower bound can therefore be selected during installation. The project has no lock file, exact version pins, package hashes, or recorded transitive dependency set. Python package installation and import are code-execution boundaries. A compromised upstream release, maliciously modified transitive dependency, or unexpectedly incompatible future version could execute code during installation or when imported by the report generator. The reviewed package names are not apparent typosquatting names, and no currently malicious package version was established by this static audit. The confirmed weakness is the project’s inability to reproduce or cryptographically verify the reviewed dependency set. ### Attack Path 1. A future direct or transitive package release satisfies one of the broad `>=` constraints. 2. That release is compromised, malicious, or otherwise unsafe. 3. A user follows the documented `pip3 install -r requirements.txt` command. 4. The package manager resolves and downloads the new release because no exact version or hash prevents it. 5. Package installation hooks or later imports execute the changed package code under the user’s privileges. 6. The package receives the same filesystem and network access as the report generator. ### Impact Assessment If an unsafe package ve ...[truncated 689 chars]
    Remediation
    View remediation
    Vulnerability Patterns
    • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
    • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
    • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
    • Behavioral ASTexec() Call, eval() Call, Dynamic Import
    • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
    Findings (22)

    Natural-Language Policy Violations

    Medium
    Category
    Not specified by scanner
    Confidence
    95% confidence
    Finding

    The natural-language content of the skill description is entirely in Chinese, including usage and output descriptions, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-language audience. Under the policy criteria, forcing a specific language without user 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
    93% confidence
    Finding

    The README describes the skill entirely as an A-share financial report generator in Chinese, with no indication that users can choose another language or locale. Under the policy, forcing a specific language or locale without opt-in is a natural-language policy violation unless the constraint is clearly documented and justified as region-specific.

    Content

    No source excerpt is available for this finding.

    Undeclared Tool Scope

    Medium
    Category
    MCP Least Privilege
    Confidence
    93% confidence
    Finding

    The skill invokes Python scripts that fetch remote market/news data and relies on shell-based setup/install commands, yet the manifest does not declare any explicit tool scope such as network or shell permissions. This creates a permission-transparency gap: an agent or reviewer cannot easily constrain or audit what the skill is allowed to do, increasing the risk of unintended command execution or network access beyond user expectations.

    Content

    No source excerpt is available for this finding.

    Vague Triggers

    Medium
    Category
    Not specified by scanner
    Confidence
    95% confidence
    Finding

    The trigger set includes broad phrases like '金融报告', '投研报告', '股票分析', and 'A股研报', which are generic enough to match ordinary conversation and unintentionally invoke the skill. In a skill that performs network access, package installation, and report generation, accidental activation can cause unexpected external data retrieval and local command execution.

    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 includes a natural-language comment indicating Chinese font usage and unconditionally sets matplotlib sans-serif fonts to Chinese-oriented font families. This enforces a specific locale/language presentation behavior without any user opt-in or documented justification, which matches the language/locale policy violation category.

    Content

    No source excerpt is available for this finding.

    Natural-Language Policy Violations

    Medium
    Category
    Not specified by scanner
    Confidence
    94% confidence
    Finding

    The module docstring is entirely in Chinese and presents the skill's purpose and source-selection behavior in a single fixed language. Under the policy, forcing a specific language or locale without offering user choice or documenting a justified region-specific constraint is 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
    95% confidence
    Finding

    The module docstring presents the tool name and usage only in Chinese, and the rest of the script continues this pattern. This imposes a specific language/locale on users without an explicit opt-in or documented region-specific justification, which matches the language-policy violation category.

    Content

    No source excerpt is available for this finding.

    Natural-Language Policy Violations

    Medium
    Category
    Not specified by scanner
    Confidence
    97% confidence
    Finding

    The module description and all generated report content are hard-coded in Chinese, and the HTML output explicitly sets lang="zh-CN". There is no user opt-in, language selection mechanism, or documented region-specific constraint justifying the forced locale.

    Content

    No source excerpt is available for this finding.

    Context-Inappropriate Capability

    Medium
    Category
    Not specified by scanner
    Confidence
    93% confidence
    Finding

    The skill's stated purpose is to generate weekly A-share research reports as PDF documents, and rendering HTML to PDF is expected. However, this function goes beyond library-based rendering and conditionally invokes an external gs binary via subprocess.run, introducing process-execution capability that is not justified or disclosed by the manifest for a finance reporting skill.

    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 · scripts/report_generator.py (reported line 426)May include surrounding context.

    python
    gs_bin = shutil.which("gs")
        if gs_bin:
            try:
                subprocess.run([
                    gs_bin, "-dNOPAUSE", "-dBATCH", "-dSAFER",
                    "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4",
                    "-dPDFSETTINGS=/prepress",
    

    Natural-Language Policy Violations

    Medium
    Category
    Not specified by scanner
    Confidence
    96% confidence
    Finding

    This code file contains natural-language documentation and output strings exclusively in Chinese, including the module description and the summary returned to callers. Under the stated policy, forcing a specific language without user opt-in is a locale-policy violation unless the constraint is explicitly justified, which is not present here.

    Content

    No source excerpt is available for this finding.

    Natural-Language Policy Violations

    Low
    Category
    Not specified by scanner
    Confidence
    91% confidence
    Finding

    This markdown skill output presents its title and the rest of the report in Chinese, and nowhere indicates that the user can choose another language or that the report is intentionally limited to a Chinese-speaking or region-specific audience. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

    Content

    No source excerpt is available for this finding.

    Unpinned Dependencies

    Low
    Category
    Supply Chain
    Confidence
    98% confidence
    Finding

    The dependency is specified with a lower bound only, so builds may resolve to different versions over time. This weakens reproducibility and can silently introduce vulnerable or incompatible releases through normal package updates or supply-chain compromise.

    Content

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

    text
    akshare>=1.10.0
    pandas>=1.5.0
    numpy>=1.23.0
    weasyprint>=60.0
    

    Unpinned Dependencies

    Low
    Category
    Supply Chain
    Confidence
    99% confidence
    Finding

    The pandas requirement is unpinned, which means the installed version is nondeterministic and may drift to a release with known flaws or breaking behavior. In security-sensitive data/report pipelines, lack of pinning increases supply-chain risk and makes incident response harder.

    Content

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

    text
    akshare>=1.10.0
    pandas>=1.5.0
    numpy>=1.23.0
    weasyprint>=60.0
    matplotlib>=3.7.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
    86% confidence
    Finding

    Because pandas is not pinned, it is impossible to verify from this manifest whether a vulnerable or unaffected version will be installed. This is a real security hygiene issue even though the cited advisory is disputed, since the absence of version pinning prevents reliable vulnerability assessment.

    Content

    No source excerpt is available for this finding.

    Unpinned Dependencies

    Low
    Category
    Supply Chain
    Confidence
    99% confidence
    Finding

    Using numpy>=1.23.0 allows any newer version to be installed, including versions not tested by the skill author. This creates avoidable supply-chain exposure and undermines reproducible deployments.

    Content

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

    text
    akshare>=1.10.0
    pandas>=1.5.0
    numpy>=1.23.0
    weasyprint>=60.0
    matplotlib>=3.7.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
    93% confidence
    Finding

    The numpy entry cannot be assessed against its advisories because the requirement is open-ended. That uncertainty is itself a supply-chain weakness: deployments may resolve to different versions, including ones with known defects, without visibility.

    Content

    No source excerpt is available for this finding.

    Unpinned Dependencies

    Low
    Category
    Supply Chain
    Confidence
    99% confidence
    Finding

    An unpinned weasyprint dependency is more concerning because this package processes HTML/CSS and renders PDFs, a feature area that has historically seen SSRF and file-handling issues. Allowing arbitrary future versions without review can expose the report generator to network/file access bugs introduced upstream.

    Content

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

    text
    akshare>=1.10.0
    pandas>=1.5.0
    numpy>=1.23.0
    weasyprint>=60.0
    matplotlib>=3.7.0
    

    Unverifiable Dependency: weasyprint has 8 known advisory(ies) (CVE-2024-28184 (WeasyPrint allows the attachment of arbitrary files and URLs to a PDF); CVE-2025-68616 (WeasyPrint has a Server-Side Request Forgery (SSRF) Protection Bypass via HTTP R); CVE-2026-55073 (weasyprint Has Server-Side Request Forgery (SSRF)) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

    Low
    Category
    Supply Chain
    Confidence
    97% confidence
    Finding

    WeasyPrint has a history of security-relevant issues affecting PDF generation, file attachment handling, and SSRF-like behavior, and the manifest does not pin the version. In a report-generation skill that likely consumes remote financial data and renders PDFs, inability to verify the installed release materially increases risk.

    Content

    No source excerpt is available for this finding.

    Unpinned Dependencies

    Low
    Category
    Supply Chain
    Confidence
    97% confidence
    Finding

    The matplotlib package is also unpinned, so environments may install differing versions over time. While often lower risk than network-facing packages, this still contributes to supply-chain uncertainty and inconsistent behavior.

    Content

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

    text
    pandas>=1.5.0
    numpy>=1.23.0
    weasyprint>=60.0
    matplotlib>=3.7.0
    

    Intent-Code Divergence

    Low
    Category
    Not specified by scanner
    Confidence
    89% confidence
    Finding

    The render_pdf docstring says the function renders HTML to PDF 'through Ghostscript optimization', implying Ghostscript-based post-processing is part of the function's behavior. In reality, the code first writes the PDF with WeasyPrint and only invokes Ghostscript if gs is present; otherwise it simply renames the temporary PDF, so the documentation overstates what the function does.

    Content

    No source excerpt is available for this finding.

    Missing User Warnings

    Low
    Category
    Not specified by scanner
    Confidence
    78% confidence
    Finding

    render_pdf writes a temporary PDF and then replaces or creates the final file at output_path, which affects user data on disk. While the function docstring explains the conversion, it does not warn about overwriting the destination path or disclose the file-write side effect to the user.

    Content

    No source excerpt is available for this finding.

    Static analysis

    No suspicious patterns detected.