Back to skill

Security audit

Ai Policy Brief

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Chinese AI policy crawler and brief generator; the main risks are dependency and web-crawling integrity issues, not hidden or destructive behavior.

Install it in a dedicated virtual environment, expect it to make outbound requests to Chinese government, media, and smartcity.team sources, and verify important policy claims against official HTTPS government pages before relying on the brief.

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)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:13
Finding

Unpinned Third-Party Dependencies Installed from a Mutable Package Index

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:13-17
Vulnerability Type: Unpinned dependency installation
Risk Level: Medium

Vulnerable Code

markdown
> **Before first use**, run the following command in a terminal to install crawler dependencies:
>
> ```bash
> pip install requests beautifulsoup4 lxml python-dateutil
> ```

Technical Analysis

The installation command retrieves the latest available versions of four packages without version constraints, integrity hashes, or a reviewed lock file. Consequently, the code installed and imported by the Skill can change after the Skill package itself has been audited.

No evidence was found that the named dependencies are currently malicious. The vulnerability is the absence of controls ensuring that future installations reproduce reviewed dependency versions. Package installation and module import can execute package-controlled Python code in the context of the user running the Skill.

Attack Path

  1. An attacker compromises a dependency publisher account, package release process, or package-index delivery path.
  2. The attacker publishes a malicious version under one of the dependency names.
  3. A user follows the mandatory setup instruction and runs the unpinned pip install command.
  4. pip downloads and installs the malicious release.
  5. Malicious package code executes during installation or when fetch_policy.py imports the package.

Impact Assessment

The malicious package would run with the privileges of the user or service account executing pip or the crawler. Depending on those privileges, it could read accessible local files, steal credentials, alter the Python environment, make outbound requests, or modify user-owned files.

The project does not request administrative privileges, so privilege escalation is not inherent. The practical impact is bounded by the permissions of the account running the installation.

Remediation
View remediation

Remediation Suggestions

  1. Define reviewed, exact versions in a requirements file:
    text
    requests==REVIEWED_VERSION
    beautifulsoup4==REVIEWED_VERSION
    lxml==REVIEWED_VERSION
    python-dateutil==REVIEWED_VERSION
    
  2. Generate and verify cryptographic hashes for every package and transitive dependency.
  3. Install with:
    bash
    python -m pip install --require-hashes -r requirements.txt
    
  4. Use a dedicated virtual environment with no unnecessary filesystem or credential access.
  5. Add automated dependency vulnerability and provenance scanning.
  6. Review and deliberately update the lock file rather than automatically accepting new releases.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_policy.py:491
Finding

Policy and News Content Retrieved over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_policy.py:491-499, scripts/fetch_policy.py:568-580
Vulnerability Type: Unauthenticated plaintext network communication
Risk Level: Medium

Vulnerable Code

python
def crawl_gd(days, keywords):
    """Guangdong Provincial People's Government"""
    source = "Guangdong Province"
    results = []
    for url in [
        "http://www.gd.gov.cn/zwgk/wjk/index.html",
        "http://www.gd.gov.cn/zwgk/gsgg/index.html",
    ]:
        html = fetch_html(url)
        results.extend(parse_generic_list(html, url, source, "guangdong"))
    return results

Additional plaintext endpoints are used by the media crawlers:

python
if not items:
    url2 = "http://www.xinhuanet.com/tech/"
    html2 = fetch_html(url2)
    items = parse_generic_list(html2, url2, source, "media")
return items


def crawl_people(days, keywords):
    """People's Daily"""
    source = "People's Daily"
    url = "http://politics.people.com.cn/GB/1024/index.html"
    html = fetch_html(url)
    items = parse_generic_list(
        html, "http://www.people.com.cn", source, "media"
    )
    return items

Technical Analysis

HTTP does not provide server authentication, confidentiality, or response integrity. An attacker controlling a network gateway, proxy, DNS path, or other on-path component can modify the returned HTML before it reaches the crawler.

The crawler parses titles, dates, and links from these responses and exposes the resulting records to the Agent as policy data. Therefore, transport tampering can directly affect material presented as authoritative policy information.

Although fetch_html supports TLS verification for HTTPS URLs, that verification offers no protection to these plaintext endpoints. The code also allows redirects, so an HTTP endpoint can redirect processing to another untrusted destination.

Attack Path

...[truncated 1060 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace every plaintext endpoint with its verified HTTPS equivalent.
  2. Fail closed if an HTTPS endpoint is unavailable rather than falling back to HTTP.
  3. Reject HTTPS-to-HTTP redirect downgrades.
  4. Validate the final response URL after redirects and require an allowlisted HTTPS host.
  5. Add transport-security tests that fail if any crawler URL begins with http://.
  6. Clearly mark data from non-government media or aggregation services as secondary and independently verify high-impact claims against official HTTPS sources.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_policy.py:195
Finding

Unrestricted Redirects and Insufficient Validation of Scraped Links

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch_policy.py:195-201, scripts/fetch_policy.py:340-365, scripts/fetch_policy.py:750-767
Vulnerability Type: Untrusted remote-content and URL handling
Risk Level: Medium

Vulnerable Code

Network requests follow redirects without validating the destination:

python
resp = requests.get(
    url,
    headers=get_headers(referer=url),
    timeout=REQUEST_TIMEOUT,
    allow_redirects=True,
    verify=verify_ssl
)

Parsed links are normalized but are not restricted to HTTPS or an explicit source-domain allowlist:

python
href = link_el.get('href', '')
if not title or not href or len(title) < 5:
    continue
url = urljoin(base_url, href)

items.append({
    'title': title,
    'url': url,
    'date_text': date_text,
    'source': source_name,
    'source_type': source_type,
})

When snippet collection is enabled, the scraped URL is fetched again:

python
def fetch_snippet(url: str, max_chars: int = 200) -> str:
    try:
        html = fetch_html(url, retries=1, sleep_range=(0.2, 0.5))
        if not html:
            return ""
        soup = BeautifulSoup(html, 'lxml')
        for tag in soup(['script', 'style', 'nav', 'header', 'footer']):
            tag.decompose()
        content = soup.select_one(
            'div.article, div.content, div#content, div.main-content, '
            'div.text, article, div.zwyw_content, div.article-content'
        )
        text = (content or soup.body or soup).get_text(
            separator=' ', strip=True
        )
        text = re.sub(r'\s+', ' ', text)
        return text[:max_chars]

Technical Analysis

requests.get follows redirects by default when allow_redirects=True, including cross-domain redirects. The code does not validate the final URL, enforce an allowed scheme, or ensure that the destination remains within the expe ...[truncated 2115 chars]

Remediation
View remediation

Remediation Suggestions

  1. Disable automatic redirects and validate each redirect manually:
    python
    requests.get(url, allow_redirects=False, ...)
    
  2. Maintain an explicit allowlist of approved HTTPS hostnames for every crawler.
  3. Validate both the initial URL and final redirect destination.
  4. Reject non-HTTP protocols, plaintext HTTP, embedded credentials, unexpected ports, IP-literal hosts, localhost, private networks, loopback ranges, and link-local destinations.
  5. Resolve hostnames and revalidate resolved addresses before connection to mitigate DNS rebinding.
  6. Ensure parsed article links remain on an approved source domain before including or fetching them.
  7. Treat all remote titles and snippets as untrusted data. Add explicit Agent instructions never to follow commands embedded in retrieved content.
  8. Keep snippet fetching disabled by default and require an explicit, documented option to enable it.
  9. Apply outbound network restrictions at the operating-system or container level so the crawler can reach only approved public source domains.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared purpose says the skill aggregates domestic AI policy updates for national and Guangdong/Guangzhou sources, but the behavior expands to multiple media outlets and a third-party aggregation site and relies on a crawler returning raw JSON. This mismatch undermines informed consent and trust boundaries, because users may believe only official policy sources are being queried while the skill actually collects broader external content with different reliability and privacy implications.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill clearly directs the agent to run a local Python crawler and perform outbound requests, but it does not declare any explicit tool scope such as allowed tools or network permissions. This creates a capability-transparency gap: users and hosting systems cannot reliably constrain or audit what the skill is allowed to execute, increasing the risk of unauthorized code execution or unintended network access.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description and all user interaction examples require Chinese-language prompts and outputs, but the file does not state that this is an optional locale setting or a justified region-specific constraint. Under the language/locale policy, forcing a single language without opt-in is a natural-language policy issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly instructs the AI to invoke an exec tool to run a local Python script that crawls 14 websites, while also saying the user need not do anything manually. Automatic execution of code plus silent network access is dangerous because it removes user awareness and approval for actions that may consume resources, expose environment details, or contact untrusted third-party sites.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file is natural-language skill content, and it appears to require Chinese reading ability throughout the document. Under the policy rule, forcing a specific language without user opt-in or a clearly documented justification is a language/locale policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Manifest强调覆盖政府政策动态并提供简报式解读,文件头注释也写明“爬取国内各政府官网和权威媒体的AI相关政策”。但注册的爬虫不仅包含国务院、部委、广东/广州政府站点,还包含澎湃、新浪、凤凰网、央视、人民日报、新华社以及 smartcity.team 行业政策库,这些来源会返回新闻/行业文章而不只是政策文件,超出了“政策聚合”的语义边界。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code hard-codes Accept-Language to prefer zh-CN, which enforces a specific locale for all outbound requests. The file does not offer a user choice or document a justified region-specific constraint, so it matches the language/locale policy-violation criterion.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Manifest说明技能会“提供简报式解读”,但该脚本最终输出的只是查询日期、时间范围、关键词、总数和原始结果列表,结果项也仅含标题、URL、日期、来源及可选片段。代码中没有摘要、解读、归纳、趋势分析或 briefing 生成逻辑,因此与描述中的“简报式解读”存在能力缺失。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.