Back to skill

Security audit

Smart Web Fetch Safe

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent web-fetching utility, but its default unrestricted URL fetching can expose internal services or sensitive network-only content from the agent environment.

Review before installing in any environment with access to internal networks, localhost services, cloud metadata, or sensitive intranet pages. Prefer running it in a network-restricted sandbox, configure an explicit allowlist, avoid remote mode for sensitive URLs, and pin dependencies before operational use.

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

Error
Location
scripts/fetch.py:132
Finding
Unrestricted Server-Side Request Forgery and Redirect-Based Allowlist Bypass<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch.py:33-40`, `scripts/fetch.py:102-109`, `scripts/fetch.py:132-144`, and `scripts/fetch.py:195-207` **Vulnerability Type**: Server-Side Request Forgery (SSRF) and incomplete destination validation **Risk Level**: High ### Vulnerable Code ```python def is_domain_allowed(url: str) -> bool: """Check whether the domain is on the allowlist.""" if not ALLOWED_DOMAINS: return True parsed = urlparse(url) allowed = [d.strip() for d in ALLOWED_DOMAINS.split(",")] return parsed.netloc in allowed or any( parsed.netloc.endswith("." + d) for d in allowed ) ``` ```python def fetch_remote(url: str, max_chars: int = DEFAULT_MAX_CHARS) -> dict: """Remote cleaning mode using Jina Reader.""" try: clean_url = url.replace("https://", "").replace("http://", "") jina_url = JINA_READER_URL.format(url=clean_url) response = requests.get(jina_url, timeout=30) response.raise_for_status() ``` ```python def fetch_local(url: str, max_chars: int = DEFAULT_MAX_CHARS) -> dict: """Local parsing mode.""" try: headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } response = requests.get(url, headers=headers, timeout=30) response.raise_for_status() content = clean_html_local(response.text, max_chars) ``` ```python use_remote = args.remote or (DEFAULT_MODE == "remote" and not args.local) if use_remote: result = fetch_remote(url, args.max_chars) if not result["success"]: print( f"Remote fetch failed: {result['error']}, falling back to local...", file=sys.stderr ) result = fetch_local(url, args.max_chars) else: result = fetch_local(url, args.max_chars) ``` ### Technical Analysis The Skill accepts a caller-provided URL and issues an HTTP request from the Agent environment. When `ALLOWED_DOMAINS ...[truncated 3574 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an explicit destination allowlist instead of allowing every domain when configuration is absent. 2. Parse the URL before use and permit only the `http` and `https` schemes. 3. Reject URLs containing embedded credentials unless they are explicitly required. 4. Resolve the hostname and reject every address in loopback, private, link-local, multicast, unspecified, reserved, and other non-public ranges. 5. Explicitly block known cloud metadata destinations, including link-local metadata addresses and provider-specific metadata hostnames. 6. Disable automatic redirects with `allow_redirects=False`, or process redirects manually and apply the complete scheme, hostname, port, DNS, and IP validation policy to every redirect target. 7. Revalidate the resolved destination immediately before connecting to reduce DNS-rebinding exposure. 8. Normalize hostnames using a strict IDNA-aware parser and compare hostname values rather than `netloc`, which can include ports and credentials. 9. Restrict destination ports to those required by the Skill, normally TCP 80 and 443. 10. Apply outbound firewall or sandbox rules so the Skill process cannot reach internal networks or metadata services even if application-level validation fails. 11. Do not automatically fall back from remote retrieval to local retrieval. Require explicit user consent before changing which system contacts the target. 12. Add tests covering direct private addresses, IPv6 loopback, decimal or encoded IP representations, redirects to private addresses, DNS results containing private addresses, embedded credentials, and metadata endpoints. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:74
Finding
Unpinned Third-Party Dependencies Create a Non-Reproducible Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:74-78` **Vulnerability Type**: Unpinned runtime dependencies and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash pip install beautifulsoup4 requests ``` ### Technical Analysis The documented installation command installs `beautifulsoup4` and `requests` without specifying reviewed versions, hashes, or a locked transitive dependency set. As a result, the code installed by users can change over time even though the Skill package itself remains unchanged. No evidence of a typosquatted package, malicious package name, or untrusted custom package index was found. The risk arises from mutable dependency resolution: future package releases and transitive dependencies are outside the reviewed artifact and are selected at installation time. The command also relies on the user's configured Python package index. If that configuration points to an untrusted or compromised source, packages with the expected names could be substituted. Without hashes, `pip` cannot verify that downloaded artifacts match a previously reviewed set. ### Attack Path 1. A user follows the installation instructions in `SKILL.md`. 2. `pip` queries the package indexes configured in the user's environment. 3. It selects the currently available versions of `beautifulsoup4`, `requests`, and their transitive dependencies. 4. A compromised, malicious, or unexpectedly changed release is downloaded because no version or artifact hash is enforced. 5. Package installation code or imported runtime code executes with the privileges of the user running the Skill. This path depends on compromise or unsafe configuration outside the repository; the audited project does not itself identify or intentionally request a malicious dependency. ### Impact Assessment A compromised dependency could execute Python code with the same privileges as the Skill process. Potential consequences include: - Reading files and environment ...[truncated 490 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dependency lock file containing reviewed exact versions for direct and transitive dependencies. 2. Pin every package to an exact version rather than using unconstrained package names. 3. Record cryptographic hashes for approved distribution artifacts. 4. Install with hash verification, for example: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 5. Use a trusted package index explicitly and prevent unintended fallback to additional indexes. 6. Regularly scan the locked dependency set for known vulnerabilities. 7. Review and deliberately update the lock file rather than accepting automatic upgrades. 8. Run the Skill in an isolated virtual environment or container with minimal filesystem and network privileges. 9. Document the supported Python version so dependency resolution remains reproducible across environments. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill documentation declares executable capabilities that can access environment configuration and perform network requests, but it does not define an explicit tool scope such as permissions or allowed-tools. This creates an authorization gap where an agent or operator may invoke the skill without clear policy constraints, increasing the risk of unintended external access or data exposure, especially because the skill supports optional remote processing through a third-party service.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The skill is presented as privacy-first and local-first, but it can fetch arbitrary URLs and optionally relay requests through a third-party service. In an agent setting, this mismatch can cause unintended disclosure of user-supplied URLs or internal resource targets and weakens safety expectations around network access.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The remote cleaning path sends the target URL to an external service, which can expose sensitive browsing targets, internal URLs, or user workflow data to a third party. Because the relay happens in code without an explicit consent checkpoint near the network call, users and integrators may not realize data is leaving the local environment.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The file includes user-facing natural-language text in Chinese, such as the module description and multiple operational comments, while the skill does not indicate that it is intentionally limited to Chinese-speaking users or provide an opt-in language choice. This can violate a language/locale policy when a skill implicitly forces a specific language without user selection.

Intent-Code Divergence

Low
Confidence
83% confidence
Finding
Allowing all domains when no whitelist is configured defeats the safety posture implied by the module and enables unrestricted outbound fetching. In an agent environment, that can be abused to access attacker-chosen endpoints, including internal or sensitive network locations if network egress exists.

Static analysis

No suspicious patterns detected.