Back to skill

Security audit

Web Monitor

Security checks for vulnerabilities and agentic risk

Overview

This website-monitoring skill is mostly purpose-aligned, but it needs Review because it can fetch arbitrary URL schemes or private destinations and store retrieved content locally.

Review before installing in environments with access to private networks, cloud metadata endpoints, or sensitive local files. Use it only for intended public web pages, avoid authenticated or sensitive pages unless you want their content stored locally, and periodically inspect or delete ~/.web-monitor data.

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

Error
Location
scripts/monitor.py:48
Finding
Unrestricted URL Fetching Enables SSRF and Local File Access## Vulnerability Details **File Location**: `scripts/monitor.py`, lines 48-61 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unrestricted URI scheme access **Risk Level**: High ### Vulnerable Code ```python def fetch_content(url: str, selector: str = None, headers: dict = None) -> str: req_headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) web-monitor/2.0" } if headers: req_headers.update(headers) req = Request(url, headers=req_headers) try: with urlopen(req, timeout=30) as resp: raw = resp.read().decode("utf-8", errors="replace") except HTTPError as e: raise RuntimeError(f"HTTP {e.code}: {e.reason}") ``` ### Technical Analysis The URL accepted by the `add` command is passed directly to `urllib.request.Request` and `urlopen` without validating its scheme, hostname, resolved IP address, port, or redirect destinations. The implementation does not: - Restrict URLs to the `http` and `https` schemes. - Reject loopback, private, link-local, reserved, multicast, or unspecified IP addresses. - Prevent access to supported local-resource schemes such as `file://`. - Validate DNS resolution results. - Revalidate destinations reached through HTTP redirects. - Restrict access to cloud instance metadata services. - Impose a maximum response size before reading the response into memory. Although outbound network access is necessary for the declared website-monitoring functionality, unrestricted access to local resources and private networks exceeds the minimum privileges needed to monitor public web pages. There is no evidence that the code deliberately transmits credentials, environment variables, snapshots, or local files to a hardcoded third party. The principal risk is that attacker-controlled URLs can cause the process to retrieve sensitive resources, after which their contents may be stored ...[truncated 1782 chars]
Remediation
## Remediation Suggestions 1. **Restrict URI schemes** - Parse URLs with `urllib.parse.urlsplit`. - Permit only explicit `http` and `https` schemes. - Reject URLs containing unsupported schemes, missing hostnames, or embedded credentials. 2. **Validate resolved destinations** - Resolve the hostname before making a request. - Use Python's `ipaddress` module to reject every resolved loopback, private, link-local, multicast, reserved, or unspecified address. - Explicitly block cloud metadata destinations such as `169.254.169.254`. - Apply validation to both IPv4 and IPv6 addresses. 3. **Secure redirect handling** - Disable automatic redirects or implement a custom redirect handler. - Parse, resolve, and validate every redirect destination before following it. - Set a small maximum redirect count. 4. **Reduce DNS rebinding exposure** - Ensure that the address validated is the address used for the connection. - Where feasible, use an outbound proxy or network policy that blocks private and link-local destinations. 5. **Limit resource consumption** - Inspect `Content-Length` when available. - Read responses incrementally and stop after a configured maximum number of bytes. - Apply limits to snapshot and diff retention. 6. **Apply deployment-level controls** - Run the Skill under a dedicated, low-privilege account. - Deny unnecessary filesystem access. - Restrict outbound traffic to approved public destinations where the environment permits it. - Consider an explicit hostname allowlist when monitoring targets can be supplied by untrusted parties. 7. **Add security tests** - Verify rejection of `file://` URLs. - Verify rejection of loopback, RFC1918, link-local, metadata, IPv6-local, and alternate numeric IP representations. - Verify that redirects and DNS changes cannot bypass destination validation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises capabilities that include network access plus local file and environment access, but it does not declare any explicit tool scope or permissions boundaries. That makes the operational trust model unclear and increases the risk of unintended invocation or overly broad execution in environments that rely on manifest-declared constraints.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The description contains broad trigger phrases like watching websites, tracking changes, checking updates, and monitoring content, which can match many ordinary user requests. Overbroad routing can cause the skill to activate unexpectedly and perform network fetches or local storage actions in contexts where the user did not clearly consent to this skill's behavior.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill text explains functionality but does not clearly warn that fetched page content is stored locally in persistent snapshots and diffs. This can create privacy and data-retention risk if monitored pages contain sensitive, copyrighted, personalized, or session-dependent content that users may not expect to be written to disk.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The code stores an alert_on_keywords_only flag when a watch is added, and the CLI help says '--keywords-only' means 'Only alert on keyword matches, not all changes'. However, cmd_check never reads this flag and still reports generic page changes whenever content differs, so the implemented behavior does not match the declared feature/intent.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This markdown file explains that the skill stores tracked URLs, page snapshots, diffs, and alert records under `~/.web-monitor/`, but it does not include a warning about the privacy implications of retaining fetched web content locally. Because markdown files should warn about behaviors that may affect user data or privacy, the omission is notable even though the storage location is documented.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The comment states 'Keyword check — only on ADDED text (new content from diff)', but when no prior snapshot exists the code sets added_text = new_content and runs keyword matching against all current page content. That documentation is actively misleading about when alerts can trigger.

Static analysis

No suspicious patterns detected.