Back to skill

Security audit

网页内容监控

Security checks for vulnerabilities and agentic risk

Overview

The skill is a plausible webpage monitor, but it fetches arbitrary URLs and stores full fetched content locally in a way that is broader than its documentation makes clear.

Install only if you are comfortable with the skill reading any URL the agent is asked to monitor and saving the fetched page contents under your home directory. Use it only for non-sensitive public pages unless you add URL validation, restrictive file permissions, and retention limits.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/monitor_page.py:20
Finding
Unrestricted URL Fetching Enables SSRF and Local File Access## Vulnerability Details **File Location**: `scripts/monitor_page.py`, lines 20-24 **Vulnerability Type**: Server-Side Request Forgery and local resource access **Risk Level**: High ### Vulnerable Code ```python def fetch_page(url: str) -> str: try: import urllib.request req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=10) as r: return r.read().decode("utf-8", errors="ignore") except Exception as e: return f"[ERROR fetching page: {e}]" ``` The value passed to this function originates directly from the required command-line argument: ```python p.add_argument("--url", required=True) ``` ### Technical Analysis The application passes an unrestricted, user-controlled URL to `urllib.request.urlopen()`. It does not validate the URL scheme, destination hostname, resolved IP address, port, or redirect chain. This allows a caller to request resources outside the intended scope of public webpage monitoring. Depending on the protocols supported by the runtime, requests can include local-file URLs as well as HTTP endpoints on loopback, private, link-local, or otherwise internal networks. The ten-second timeout limits request duration but does not prevent access to unauthorized destinations. Redirects also require validation because an apparently public URL could redirect to a prohibited internal address. ### Attack Path 1. An attacker or untrusted user controls the value supplied through `--url`. 2. The attacker supplies a local resource URL such as a `file://` URL, or an HTTP URL targeting a loopback, private-network, or cloud metadata service. 3. `fetch_page()` passes the value directly to `urllib.request.urlopen()`. 4. The request executes with the network reachability and file permissions of the monitoring process. 5. The returned content is processed as monitored page data. 6. `monitor()` ...[truncated 906 chars]
Remediation
## Remediation Suggestions 1. Parse URLs before making requests and permit only explicitly required schemes, preferably `https` and, if necessary, `http`. 2. Reject URLs containing credentials or ambiguous hostname encodings. 3. Resolve the destination hostname and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. 4. Apply the same validation after every DNS resolution and to every redirect destination. 5. Protect against DNS rebinding by connecting only to the validated resolved address while preserving the intended hostname for TLS verification. 6. Consider an explicit hostname allowlist when the intended monitoring targets are known. 7. Restrict destination ports to those required for webpage monitoring. 8. Run the monitor under a dedicated, least-privileged account with restricted filesystem and network access. 9. Return an explicit fetch failure instead of treating exception text as normal page content. 10. Add automated tests covering `file://`, loopback, private IPv4, private IPv6, link-local, encoded-address, and redirect-based bypass attempts.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/monitor_page.py:11
Finding
Fetched Content Is Persisted in Plaintext Without Explicit Restrictive Permissions## Vulnerability Details **File Location**: `scripts/monitor_page.py`, lines 11-16 and 40-41 **Vulnerability Type**: Insecure storage of potentially sensitive fetched content **Risk Level**: Medium ### Vulnerable Code ```python def save_hashes(hashes: dict): os.makedirs(MONITOR_DIR, exist_ok=True) import json with open(os.path.join(MONITOR_DIR, "hashes.json"), "w") as f: json.dump(hashes, f) ``` The entire fetched response is added to the persisted data: ```python old_hashes[url_hash] = {"content": content, "ts": datetime.now().isoformat()} save_hashes(old_hashes) ``` ### Technical Analysis Despite the name `hashes.json`, the file stores complete response bodies rather than only cryptographic hashes. The directory and file are created without explicit restrictive permissions, so their effective permissions depend on the process umask and pre-existing filesystem state. This creates a plaintext repository of all monitored content. That content may include sensitive internal data, authenticated page content, or local-file data obtained through the unrestricted URL-fetching vulnerability. The implementation also lacks retention limits and atomic file replacement. If `~/.web_monitor` or `hashes.json` already exists with permissive permissions, writing the file does not correct those permissions. The entire JSON file is rewritten directly, which can additionally leave corrupted or partially written state if execution is interrupted. ### Attack Path 1. The monitor retrieves a page or resource containing sensitive information. 2. `monitor()` inserts the complete response into the `content` field. 3. `save_hashes()` serializes all retained responses to `~/.web_monitor/hashes.json`. 4. File accessibility is determined by the process umask and any existing permissions rather than an enforced security policy. 5. Another local user or process that can read the file obtains the stored response b ...[truncated 673 chars]
Remediation
## Remediation Suggestions 1. Store only a collision-resistant digest, such as SHA-256, when full response snapshots are unnecessary. 2. If keyword transition detection requires prior state, retain only the minimum derived state needed, such as previously matched keywords. 3. If snapshots are required, document that behavior and provide an explicit opt-in setting. 4. Create `~/.web_monitor` with mode `0700` and the data file with mode `0600`. 5. Verify and correct permissions on pre-existing directories and files before reading or writing them. 6. Use atomic writes through a securely created temporary file in the same directory, set restrictive permissions, flush and synchronize it as appropriate, and then replace the destination. 7. Implement configurable retention and maximum response-size limits. 8. Avoid retaining fetch-error messages as monitored content. 9. Consider encrypting stored snapshots where sensitive content must be retained. 10. Run the script under a dedicated account and ensure the storage path is not shared with unrelated users or services.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill documents behavior that performs outbound web fetching, but it does not declare any explicit tool scope or permissions boundary. This creates a governance and least-privilege problem: an agent may be allowed to access the network implicitly without clear user visibility or policy enforcement, which is risky for a skill designed to fetch arbitrary URLs on a schedule.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The manifest description and main skill description are written entirely in Chinese, and the usage conditions are expressed only for Chinese-speaking users. There is no indication that the skill supports other languages or that the Chinese-only constraint is a justified regional requirement, which can violate language/locale policy expectations.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The script includes Chinese-only user-facing text in the module description, argument help, and printed status messages. This imposes a specific language/locale on users without opt-in or justification, which matches the language/locale policy violation criteria.

Static analysis

No suspicious patterns detected.