Back to skill

Security audit

警察执法资格考试助手

Security checks for vulnerabilities and agentic risk

Overview

The study skill is mostly coherent, but it needs review because an optional web helper can fetch any supplied URL from the user's machine.

Review before installing if your OpenClaw environment allows skills to make outbound network requests or if this helper will be exposed to user-supplied URLs. The core exam-study functions are local and low risk, but the web article fetcher should be restricted to trusted public WeChat/exam domains or disabled in sensitive environments.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pqebot-web.py:34
Finding

Unrestricted URL Fetch Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/pqebot-web.py, lines 34–50
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: Medium

Vulnerable Code

python
def fetch_weixin_article(self, url: str) -> Optional[Dict]:
    """获取微信公众号文章内容"""
    try:
        # 注意:微信公众号文章需要特殊处理,这里仅做示例
        response = self.session.get(url, timeout=10)
        if response.status_code == 200:
            # 实际中需要解析微信公众号的特殊页面结构
            return {
                "url": url,
                "title": self._extract_title(response.text),
                "content": self._extract_content(response.text),
                "publish_time": self._extract_publish_time(response.text),
                "success": True
            }
    except Exception as e:
        print(f"获取文章出错: {e}")
    
    return None

Technical Analysis

The public fetch_weixin_article method accepts an arbitrary URL and passes it directly to requests.Session.get() without validating its scheme, hostname, resolved IP address, port, or redirect destination.

Although the method is described as a WeChat article fetcher, the implementation does not restrict requests to WeChat domains. The requests library also follows HTTP redirects by default. Consequently, a caller able to control the url argument can make the application initiate requests to:

  • Loopback services such as 127.0.0.1
  • Private network ranges
  • Link-local addresses, including cloud metadata services
  • Services exposed on otherwise inaccessible internal ports
  • Public URLs that redirect to prohibited internal destinations

When a target returns HTTP status 200, up to 1,000 characters of extracted response content can be returned through the method. This creates a response-based SSRF primitive rather than only a blind SSRF condition.

The audited command-line entry point does not currently invoke this method, which reduces immediate exposure ...[truncated 1805 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply a strict destination allowlist

    • Permit only https.
    • Restrict requests to explicitly approved WeChat hostnames.
    • Compare normalized hostnames exactly or against carefully defined subdomain boundaries.
  2. Validate resolved addresses

    • Resolve the hostname before connecting.
    • Reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges.
    • Validate every resolved address to mitigate DNS rebinding and mixed public/private DNS responses.
  3. Control redirects

    • Prefer allow_redirects=False.
    • If redirects are required, validate the scheme, hostname, port, and resolved addresses at every redirect hop.
    • Set a low maximum redirect count.
  4. Restrict URL syntax

    • Reject embedded credentials, fragments, malformed hostnames, and unexpected ports.
    • Normalize internationalized domain names before allowlist comparison.
    • Do not accept non-HTTP schemes.
  5. Limit response processing

    • Stream responses and enforce a small maximum response size.
    • Set separate connection and read timeouts.
    • Restrict accepted content types to expected HTML content.
  6. Reduce exposure

    • Do not connect this method directly to untrusted Agent or web input.
    • Keep network retrieval disabled unless explicitly required.
    • Run the Skill with outbound network controls that deny private and metadata address ranges.
  7. Add security tests

    • Test rejection of loopback, RFC 1918, link-local, IPv6 local, decimal or encoded IP representations, DNS rebinding scenarios, and public-to-private redirects.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

该文档从标题到全部使用说明均仅提供中文内容,且没有说明这是可选语言、可切换语言,或该技能仅面向自愿选择中文的特定用户群。根据规则,强制特定语言而无用户选择/opt-in,属于自然语言层面的语言/地区政策风险。

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger list contains generic terms such as '公安考试', '历年真题', and '2026大纲' that are broad enough to match ordinary study-related requests outside the intended narrow skill scope. Overly broad triggers can cause unintended auto-invocation or routing hijacks, making the skill intercept unrelated user queries and increasing the chance of prompt/context confusion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This JSON file encodes the exam level and all question content exclusively in Chinese, beginning with locale-specific values such as "高级". For a skill data file, this represents a fixed language/locale choice with no documented user opt-in or alternative locale support, which matches the language/locale policy violation criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This Python file contains user-facing descriptions, menus, and prompts in Chinese, and does not offer any language or locale selection. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code's user-facing title, prompts, and descriptions are entirely in Chinese, indicating the skill is designed to operate in a single language. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not stated here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This JSON dataset stores user-facing natural-language content entirely in Chinese, beginning with locale-specific labels such as "单选题". For a general-purpose skill or content file, forcing one language without documenting user choice or region-specific scope can violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON file is entirely authored in Chinese and presents the exam outline, labels, and reference materials in a single fixed language with no indication of user language selection or opt-in. Under the stated policy category, forcing a specific language without user choice can constitute a natural-language locale policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON file stores all category names, descriptions, and exam tips exclusively in Chinese. Under the stated policy, forcing a specific language without user opt-in or a documented region-specific justification 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
83% confidence
Finding

This JSON dataset uses Chinese-language titles, questions, explanations, and notes throughout, but provides no natural-language indication that the user has opted into Chinese or that the dataset is intentionally limited to a Chinese-language audience. Under the language/locale policy rule, forcing a specific language without opt-in can be a policy concern even in data/config files.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The module and class documentation present this as a web search module, and the inline comment in search_exam_info explicitly says the current implementation returns simulated data. However, fetch_weixin_article at L34-L51 performs a real HTTP GET to any supplied URL, so the surrounding documentation/commentary gives a materially incomplete and somewhat contradictory impression about whether the module is mock-only versus actually network-active.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.