Back to skill

Security audit

财政数据采集分析

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent fiscal-data scraper, but it should be reviewed because its crawler does not strictly confine outbound requests to the stated official source and its dependencies are unpinned.

Install only in a constrained environment with no access to internal services or sensitive credentials, pin and review dependencies first, and restrict outbound network access to the intended Ministry of Finance host before using it for automated collection.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
FinancialDataCollection/src/fiscal_crawler.py:90
Finding

Unrestricted outbound requests permit server-side request forgery

Content
View full analysis

Vulnerability Details

File Location: FinancialDataCollection/src/fiscal_crawler.py, lines 90-112
Vulnerability Type: Server-Side Request Forgery through unvalidated links and redirects
Risk Level: Medium

Vulnerable Code

python
def _fetch_html(self, url: str) -> str:
    response = self.session.get(url, timeout=self.timeout)
    response.raise_for_status()
    response.encoding = response.apparent_encoding or response.encoding
    return response.text
python
href = anchor.get("href", "").strip()
if not href:
    continue
absolute_url = urljoin(page_url, href)
title = normalize_text(anchor.get_text(" ", strip=True))
if "财政收支情况" not in title:
    continue
if absolute_url in yielded:
    continue
yielded.add(absolute_url)
yield {"title": title, "url": absolute_url}

Technical Analysis

The crawler starts from a fixed Ministry of Finance URL, but it does not verify the scheme, hostname, port, or resolved IP address of links extracted from listing pages. Python's urljoin accepts absolute URLs, so an absolute attacker-controlled href replaces the trusted base URL completely.

The resulting URL is passed to requests.Session.get() without destination validation. Requests also follows HTTP redirects by default, and the redirect destinations are not validated. Consequently, either a malicious listing link or a redirect from a nominally trusted URL can cause the process to issue a GET request to an arbitrary HTTP or HTTPS endpoint.

The title filter does not provide a security boundary. A party able to modify listing content can supply a title matching the expected fiscal-report pattern while setting its link to an internal destination.

Attack Path

  1. An attacker gains the ability to alter a source listing page, compromises an upstream content-management component, or causes a trusted document endpoint to return an attacker-selected redirect.
  2. For a listing- ...[truncated 1542 chars]
Remediation
View remediation

Remediation Suggestions

  1. Allow only https URLs with the exact expected hostname, such as www.mof.gov.cn.
  2. Reject URLs containing user information, unexpected ports, fragments where inappropriate, or non-HTTP schemes.
  3. Resolve the destination and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges. Repeat this validation for every redirect target to address DNS rebinding and redirect-based bypasses.
  4. Disable automatic redirects with allow_redirects=False, then follow redirects manually only after validating each Location value.
  5. Apply the same validation to listing-page and document-page requests.
  6. Enforce outbound firewall rules so the runtime cannot access metadata services, loopback services, or internal administrative networks.
  7. Add tests for absolute external links, protocol-relative URLs, private IP literals, IPv6 loopback, encoded host representations, DNS results resolving to private addresses, and redirect chains.

A minimal hostname check should resemble:

python
from urllib.parse import urlparse

ALLOWED_HOSTS = {"www.mof.gov.cn"}

def validate_url(url: str) -> None:
    parsed = urlparse(url)
    if parsed.scheme != "https" or parsed.hostname not in ALLOWED_HOSTS:
        raise ValueError("Unapproved crawl destination")
    if parsed.port not in (None, 443):
        raise ValueError("Unapproved destination port")

This check should be supplemented with resolved-IP validation and manual redirect handling.

T08 · Insecure Dependencies

Warning
Location
FinancialDataCollection/requirements.txt:1
Finding

Unpinned third-party dependencies create a non-reproducible supply-chain boundary

Content
View full analysis

Vulnerability Details

File Location: FinancialDataCollection/requirements.txt, lines 1-4
Vulnerability Type: Unpinned package dependencies
Risk Level: Medium

Vulnerable Code

text
requests
beautifulsoup4
lxml
openpyxl

The same packages are also unpinned in FinancialDataCollection/environment.yml, lines 8-12.

Technical Analysis

Every dependency is specified without an exact version or integrity hash. Each installation can therefore resolve to whichever release is current and compatible at that time. The reviewed source does not define a lock file or hash-verified installation process.

This prevents reproducible builds and makes the effective runtime dependency set change independently of the audited project. A newly compromised, malicious, or vulnerable upstream release could be installed during a later environment creation even though the project source itself remains unchanged.

No evidence was found that the listed package names are typosquatted or currently malicious. The risk arises from unconstrained future resolution and lack of artifact integrity verification.

Attack Path

  1. An attacker compromises an upstream package release, publishing infrastructure, maintainer account, or package-distribution path for one of the named dependencies.
  2. A user follows the documented environment setup procedure after the compromised release becomes eligible for resolution.
  3. Pip resolves and downloads that release because no exact version or hash constraint excludes it.
  4. Package installation or subsequent import executes attacker-controlled package code with the privileges of the user running the setup or pipeline.
  5. The malicious dependency can access files, network resources, environment variables, and output data available to that process.

Impact Assessment

A malicious dependency can execute Python or native-extension code with the full privileges of the environment in ...[truncated 554 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin all direct and transitive dependencies to reviewed versions using a generated lock file.
  2. Use a tool such as pip-compile to produce deterministic constraints.
  3. Install with integrity verification, for example pip install --require-hashes -r requirements.lock.
  4. Keep environment.yml, direct requirements, and the lock file synchronized to avoid different resolution behavior between setup methods.
  5. Run dependency vulnerability and provenance checks in continuous integration.
  6. Update pinned versions through a controlled review process rather than resolving new releases automatically in production.
  7. Prefer an authenticated internal package mirror or allowlisted package repository for production deployments.
  8. Build and test dependencies in a restricted environment without sensitive credentials, then promote verified artifacts to the runtime environment.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language instructions in this skill are exclusively in Chinese, which effectively forces a specific language for users. Under the stated policy, this is a language/locale constraint that should either be optional for users or explicitly documented as region-specific and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file presents all operational instructions exclusively in Chinese and does not indicate that users may choose another language or that the skill is restricted to Chinese-speaking users. Under the policy for natural-language violations, forcing a specific language without user opt-in is reportable unless the locale constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code creates directories and writes period-grouped export files, and later also saves run summaries and reports, but it provides no confirmation prompt, logging, print statement, or explanatory warning comment/docstring around those filesystem writes. Because the skill persists potentially sensitive fiscal source content and derived results to disk, users are not clearly informed in this file that local files and directories will be created.

Content

No source excerpt is available for this finding.

Unbounded Output

Medium
Category
Output Handling
Confidence
75% confidence
Finding

The sheet formatter iterates every cell in every column and computes widths based on full stringified cell contents, with no bounds on row count, column count, or cell length. If upstream scraping or parsed document content is unusually large or attacker-influenced, exporting can consume excessive CPU and memory, causing denial of service or stalled runs.

Content

Scanner excerpt · FinancialDataCollection/src/fiscal_exporter.py (reported line 387)May include surrounding context.

python
cell.alignment = center_alignment

        for column_cells in sheet.columns:
            max_length = 0
            column_letter = get_column_letter(column_cells[0].column)
            for cell in column_cells:
                if cell.value is None:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill instructs the agent to run a pipeline that performs network access and writes files, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and can allow broader-than-necessary execution in environments that rely on manifest-declared capability boundaries.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description is entirely written in Chinese and frames the skill's usage, triggers, and responsibilities only in Chinese. There is no indication that users may interact in other languages or that the Chinese-only constraint is an intentional, documented regional requirement.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

若环境不存在,根据项目的 environment.yml 创建:

bash
conda env create -f $SKILL_DIR/FinancialDataCollection/environment.yml

入口脚本

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

若环境不存在,根据项目的 environment.yml 创建:

bash
conda env create -f $SKILL_DIR/FinancialDataCollection/environment.yml

入口脚本

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file documents that existing output folders may be reused or re-scraped and overwritten when data is incomplete or below a threshold. Because these behaviors affect user data on disk, the skill description should explicitly warn users that running the pipeline can overwrite prior outputs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The entire skill document is written in Chinese and provides no indication that language selection is optional or that the skill is intentionally limited to a Chinese-language or region-specific audience. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

这是一个适用于所有文件类型的自然语言政策问题。文档从标题到需求描述均明确以中文表述且未提供语言/locale 选择,可能构成未经用户选择即强制特定语言的约束。

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The requirements file specifies requests without a version constraint, making builds non-reproducible and allowing future installs to pull in vulnerable or breaking releases. In a data-collection skill that performs network access, dependency drift increases supply-chain risk and can expose the pipeline to known library flaws unexpectedly.

Content

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

text
requests
beautifulsoup4
lxml
openpyxl

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
91% confidence
Finding

The manifest does not pin requests, and the package has multiple known advisories across versions, so it is impossible to verify from this file whether deployments are safe. Because this skill performs external HTTP access, any affected requests version could increase exposure to credential leakage, TLS, redirect, or request-handling flaws depending on runtime usage.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

beautifulsoup4 is unpinned, so installations may resolve to different versions over time, reducing reproducibility and making it harder to verify whether the deployed version is secure. For a scraping-oriented skill, parser behavior changes can also silently alter scraping logic and error handling.

Content

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

text
requests
beautifulsoup4
lxml
openpyxl

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

lxml is unpinned despite being a security-sensitive parsing library with a history of advisories. In a web-scraping pipeline that parses untrusted remote HTML/XML, unresolved version selection increases the chance of pulling a release affected by parser-related vulnerabilities.

Content

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

text
requests
beautifulsoup4
lxml
openpyxl

Unverifiable Dependency: lxml has 14 known advisory(ies) (CVE-2021-43818 (lxml's HTML Cleaner allows crafted and SVG embedded scripts to pass through); CVE-2014-3146 (lxml Cross-site Scripting Via Control Characters); CVE-2021-28957 (lxml vulnerable to Cross-Site Scripting ) +11 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

lxml has known security advisories and the lack of version pinning means the installed version cannot be assessed from the manifest. This is more concerning in this skill because it scrapes and parses content from an external government website, and parser-related vulnerabilities can be triggered by malformed or hostile HTML/XML received over the network.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

openpyxl is unpinned, which creates supply-chain and reproducibility risk when generating or processing spreadsheet exports. If the skill handles workbook content from external or scraped sources, dependency drift can expose it to historical XML/entity handling issues or incompatible behavior.

Content

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

text
requests
beautifulsoup4
lxml
openpyxl

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

openpyxl has historical XML external entity-related advisories, and without pinning there is no assurance that the installed version is patched. In a skill that exports and may process Excel files, this creates uncertainty around whether spreadsheet/XML handling is protected against known issues.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The command-line description and argument help strings are written only in Chinese, which imposes a specific language on users with no documented opt-in or alternative locale support. This is a natural-language policy issue because the file hard-codes a single language for the user-facing interface.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The crawler fetches remote pages with requests.Session.get, which transmits system metadata such as the configured User-Agent and network identifiers to an external site. This code has no confirmation prompt, logging, comment, or docstring warning the user that outbound network access will occur.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The crawler filters documents by the Chinese title phrase 财政收支情况, which hard-codes a specific language/locale behavior. The file does not document that the skill is intentionally limited to Chinese Ministry of Finance content or offer any locale choice, so this is a natural-language locale constraint embedded in code.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The parser looks for Chinese-only text such as 温馨提示:您访问的页面不存在或已删除 and date/source markers like 年, 月, 日, and 来源. This enforces a specific locale in natural-language parsing logic without any visible documentation in the file that the skill is region- or language-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The file embeds Chinese-only headers, report names, and summary text throughout the exported artifacts, which forces a specific language/locale for user-visible outputs. Under the policy, locale restrictions should either be optional for the user or clearly justified as region-specific; this file provides neither.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.