Back to skill

Security audit

dabai/finance-news-brief

Security checks for vulnerabilities and agentic risk

Overview

This finance brief skill has a clear purpose, but it needs Review because it can automatically search the web, create files, install a Python package, and run Chrome with weakened isolation.

Install only if you are comfortable with a finance-report skill that performs web research, writes report files, runs a local Python script, may install a Python package automatically, and uses headless Chrome with reduced sandboxing. Prefer reviewing the script first, preinstalling pinned dependencies in an isolated environment, and confirming output paths 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 (2)

T08 · Insecure Dependencies

Warning
Location
scripts/generate_pdf.py:20
Finding
Automatic Installation of an Unpinned Runtime Dependency<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_pdf.py:20-26` **Vulnerability Type**: Unsafe runtime dependency installation **Risk Level**: Medium ### Vulnerable Code ```python def install_if_missing(package: str, import_name=None): import_name = import_name or package try: __import__(import_name) except ImportError: print(f"正在安装依赖: {package} ...") subprocess.check_call([sys.executable, "-m", "pip", "install", package, "-q"]) ``` The function is invoked during Markdown conversion: ```python def md_to_html(md_text: str) -> str: install_if_missing("markdown") ``` ### Technical Analysis The PDF generator automatically invokes `pip` when the `markdown` module is unavailable. The package version is not pinned, no package hash is verified, and no lock file or isolated environment is used. Package resolution may also be affected by the invoking environment's pip configuration, configured indexes, or package mirrors. Python packages can execute code during installation. Consequently, the script treats mutable content retrieved from a package repository as trusted executable code. Automatic environment modification is not required for Markdown-to-PDF conversion and exceeds the minimum privileges necessary for the declared functionality. This is not direct evidence that the named `markdown` package is malicious. The vulnerability is the unsafe dependency acquisition mechanism and its exposure to repository compromise, malicious mirrors, configuration manipulation, and future upstream compromise. ### Attack Path 1. The Skill is invoked on a system where the `markdown` module is not installed or cannot be imported. 2. An attacker compromises or controls a package index, configured mirror, DNS/network path, or relevant pip configuration used by the environment. 3. The script executes `python -m pip install markdown -q` without enforcing a known version or artifact hash. 4. Pip downloads and installs ...[truncated 674 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic package installation from the document-conversion path. 2. Declare dependencies in a version-controlled dependency file, such as `requirements.txt` or `pyproject.toml`. 3. Pin the exact approved package version and verify distribution hashes, for example with `pip install --require-hashes -r requirements.txt`. 4. Install dependencies during a controlled deployment or build phase rather than when processing a document. 5. Use a dedicated virtual environment or container with only the dependencies needed by the Skill. 6. Configure an explicitly trusted package index and prevent fallback to unapproved indexes. 7. If the dependency is unavailable at runtime, stop safely and provide installation instructions rather than modifying the environment automatically. 8. Periodically scan and update pinned dependencies through a reviewed change-management process. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_pdf.py:50
Finding
Untrusted HTML Rendered by Chrome with Browser Sandbox Disabled<![CDATA[ ## Vulnerability Details **File Locations**: `scripts/generate_pdf.py:50-58`, `scripts/generate_pdf.py:77-115`, and `scripts/generate_pdf.py:262-267` **Vulnerability Type**: Unsafe browser configuration and insufficient isolation of input-derived HTML **Risk Level**: High ### Vulnerable Code Markdown content is converted into HTML without an explicit sanitization step: ```python def md_to_html(md_text: str) -> str: install_if_missing("markdown") import sys as _sys import site _sys.path.insert(0, site.getusersitepackages()) import markdown return markdown.markdown( md_text, extensions=["tables", "fenced_code", "nl2br"], ) ``` The directory containing the generated HTML is exposed through a temporary loopback HTTP server, and Chrome is launched with its sandbox disabled: ```python # 1. 起临时 HTTP server,从 html 所在目录服务文件 with socket.socket() as s: s.bind(("127.0.0.1", 0)) http_port = s.getsockname()[1] serve_dir = str(html_path.parent) handler_cls = functools.partial( http.server.SimpleHTTPRequestHandler, directory=serve_dir, ) handler_cls.log_message = lambda *a: None http_server = http.server.HTTPServer(("127.0.0.1", http_port), handler_cls) http_thread = threading.Thread(target=http_server.serve_forever) http_thread.daemon = True http_thread.start() page_url = f"http://127.0.0.1:{http_port}/{html_path.name}" # 2. 找一个空闲的远程调试端口 with socket.socket() as s: s.bind(("127.0.0.1", 0)) debug_port = s.getsockname()[1] # 3. 启动 Chrome,开启远程调试 chrome_proc = subprocess.Popen( [ chrome, "--headless=new", "--disable-gpu", "--no-sandbox", "--disable-extensions", f"--remote-debugging-port={debug_port}", "--no-first-run", "--no-default-browser-check", ], stdout=subprocess.DEVNULL, stderr=su ...[truncated 3304 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox`. If Chrome cannot run sandboxed in the current environment, correct the deployment configuration rather than disabling the security boundary. 2. Render documents under a dedicated, unprivileged operating-system account or in a tightly restricted container. 3. Sanitize generated HTML with an allowlist-based sanitizer before rendering. Remove scripts, event-handler attributes, embedded frames, dangerous URLs, and other active content. 4. Disable JavaScript for PDF conversion when it is not required. 5. Apply a restrictive Content Security Policy that blocks scripts, plugins, frames, external connections, and remote resource loading. 6. Block outbound network access and access to unrelated loopback services for the rendering process. 7. Create a fresh temporary directory with restrictive permissions and place only the generated HTML and required static assets in it. 8. Use that dedicated directory as the HTTP document root instead of `output_path.parent`. 9. Prefer a `file:` URL or a purpose-built renderer when this can be done safely without exposing an HTTP document root. 10. Use a unique temporary Chrome profile and delete it after conversion. 11. Keep Chrome fully patched and enforce time, memory, process, and file-system limits around document rendering. 12. Validate the input and output paths and reject sensitive or overly broad directories as rendering roots. ]]>
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 (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
代码的核心功能是一个 PDF 生成脚本:读取指定 Markdown 文件,转为 HTML,套用模板,并调用本地 Chrome 的 DevTools Protocol 输出 PDF。这可以视为声明中“输出正式 PDF 文件(含封面)”这一子能力的部分实现,但远不足以覆盖该 skill 的主要宣称用途。声明的主功能是财经新闻搜集与中文简报生成,而代码没有任何网络抓取/新闻源访问/内容聚合/摘要生成/市场板块分类等逻辑;也没有触发器实现。因此描述与实际行为存在明显的实质性不匹配。

Vague Triggers

High
Confidence
95% confidence
Finding
The trigger rules are overly broad and force activation for common finance-related questions, which can cause the agent to perform network searches, file creation, and PDF generation when a simple conversational answer would suffice. Over-triggering expands the attack surface and may lead to unnecessary tool use without clear user intent for external actions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill uses network access, file writes, and shell execution but does not declare any explicit tool scope or permission boundaries. This increases the chance of over-privileged execution and makes it harder for a host system or reviewer to constrain risky actions such as writing files or launching Python with dependency installation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The description requires generating the brief in Chinese and later instructs that each news item be written as a concise Chinese summary. This is a natural-language locale constraint, but the file does not provide user opt-in, a language choice, or a documented reason that the skill must operate only in Chinese.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs the agent to save Markdown and PDF files into the working directory or another directory without first warning the user that local files will be created. Silent file creation can surprise users, overwrite expected outputs, or place sensitive research artifacts in locations the user did not intend.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill directs execution of a Python script via shell and states that it may install dependencies automatically. Running local commands and performing package installation without upfront warning materially increases risk because it changes the local environment, may fetch unpinned code or binaries, and can fail in unsafe or unexpected ways.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The expected output explicitly requires a "中文财经简报," and similar language appears elsewhere in the evals, but there is no indication that language selection is optional or that the skill is intentionally region-specific. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy concern.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The eval prompt uses a very broad natural-language trigger ('今天市场有什么大事?帮我搜一下最新财经新闻...') to require mandatory activation of the skill. Broad trigger conditions can cause unintended invocation in loosely related conversations, increasing the chance of unnecessary web access, file generation, and tool execution beyond user intent. In this skill's context, forced activation is more dangerous because the skill performs external search and writes Markdown/PDF files to disk.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
This expected output says the skill should generate a structured Chinese brief, but the prompt itself only asks for a report and does not establish that Chinese must always be used. Without an explicit language preference mechanism or a documented regional purpose, this can violate the language/locale policy.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring is entirely in Chinese and presents the tool's purpose and usage only in that language. This is a natural-language locale constraint that does not offer the user any language choice or document a justified region-specific limitation.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
This finding correctly captures that the skill can modify its environment by installing packages on demand. In the context of a report-generation skill, that behavior is unnecessary and expands the attack surface to package-repository compromise, dependency confusion, and unexpected system changes.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Content
def install_if_missing(package: str, import_name=None):
    import_name = import_name or package
    try:
        __import__(import_name)
    except ImportError:
        print(f"正在安装依赖: {package} ...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", package, "-q"])
Confidence
75% confidence
Finding
Dynamic __import__() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
__import__(import_name)
    except ImportError:
        print(f"正在安装依赖: {package} ...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", package, "-q"])


def find_chrome():
Confidence
95% confidence
Finding
The script automatically executes pip install at runtime. This introduces a supply-chain and arbitrary code execution risk because package installation runs code from external repositories during skill execution, which exceeds the minimum privileges expected for a PDF conversion helper.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
debug_port = s.getsockname()[1]

    # 3. 启动 Chrome,开启远程调试
    chrome_proc = subprocess.Popen(
        [
            chrome,
            "--headless=new",
Confidence
93% confidence
Finding
The script launches Chrome with headless remote debugging enabled and explicitly passes --no-sandbox. Disabling Chromium's sandbox materially weakens process isolation, so if the rendered HTML or browser engine is compromised, arbitrary code execution or local file access on the host becomes more feasible.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
for _ in range(20):
            time.sleep(0.3)
            try:
                resp = urllib.request.urlopen(
                    f"http://127.0.0.1:{debug_port}/json/version", timeout=2
                )
                info = json.loads(resp.read())
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The HTML document explicitly sets `lang="zh-CN"`, which imposes a specific language/locale. Under the policy rules, forcing a locale without user opt-in or a clearly documented region-specific justification is a natural-language policy concern.

Static analysis

No suspicious patterns detected.