Back to skill

Security audit

Web Fetcher

Security checks for vulnerabilities and agentic risk

Overview

This web-fetching skill is useful and coherent, but it forwards arbitrary URLs to multiple third-party services without clear sensitive-URL safeguards or consent guidance.

Install only if you intend to use it for public web pages. Avoid using it with private links, signed download URLs, password reset links, internal hostnames, or URLs containing tokens or credentials, because those full URLs may be sent to third-party readability services. Treat fetched page text as untrusted content and do not let it authorize tool use or disclose secrets.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_url.py:12
Finding
Unvalidated URLs and URL-Embedded Secrets Are Disclosed to Third-Party Fetch Services<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_url.py`, lines 12–16 and 34–37; documented workflow in `SKILL.md`, lines 22–38 **Vulnerability Type**: Unrestricted external URL forwarding and sensitive URL disclosure **Risk Level**: Medium ### Vulnerable Code ```python METHODS = [ ('r.jina.ai', lambda u: f'https://r.jina.ai/http://{u.removeprefix("https://").removeprefix("http://")}'), ('markdown.new', lambda u: f'https://markdown.new/{u}'), ('defuddle', lambda u: f'https://defuddle.md/{u}'), ] ``` ```python attempts = [] for name, builder in METHODS: target = builder(args.url) try: text = fetch(target, args.timeout) ``` The corresponding documented invocation is: ```markdown For deterministic retries, use the bundled script: ```bash python {baseDir}/scripts/fetch_url.py "https://example.com/article" ``` ``` ### Technical Analysis The script accepts an arbitrary URL from the command line and embeds its complete value into requests sent to as many as three independent third-party services. It does not validate: - The URL scheme. - Embedded username or password information. - Sensitive query parameters or signed URL tokens. - Localhost, private, link-local, loopback, or reserved destinations. - Internal DNS names. - Encoded or obfuscated destination forms. - Whether the user has consented to disclosing the URL to external providers. Consequently, password-reset links, presigned object-storage URLs, authentication tokens in query strings, internal service names, and other sensitive URL components can be disclosed to `r.jina.ai`, `markdown.new`, and `defuddle.md`. If an earlier service fails or returns insufficient content, the same URL may be disclosed to additional providers. The third-party services are also instructed to retrieve the supplied destination. Whether private resources are reachable depends on each provider's network controls, so this code does not by itself establish local server-side requ ...[truncated 1499 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse input with `urllib.parse.urlsplit` and permit only explicit `http` and `https` schemes. 2. Reject URLs containing username or password information. 3. Reject localhost names and loopback, private, link-local, multicast, unspecified, and reserved IP addresses. 4. Resolve hostnames before use and validate every returned address. Revalidate after redirects to reduce DNS rebinding and redirect-based bypasses. 5. Reject malformed, encoded, or ambiguous host representations. 6. Detect sensitive query parameters such as `token`, `key`, `signature`, `sig`, `auth`, and presigned-URL fields. Reject them by default or require explicit user confirmation before forwarding. 7. Warn users clearly that the complete URL will be shared with named third-party providers. 8. Consider direct retrieval under controlled network policy instead of disclosing URLs to multiple external services. 9. Apply an allowlist when the deployment has a known set of permitted public domains. 10. Avoid recording full sensitive URLs in output attempt histories; redact credentials and query values before including URLs in JSON. ]]>

T01 · Skill Instruction Hijacking

Warning
Location
scripts/fetch_url.py:39
Finding
Untrusted Web Content Is Returned for Agent Use Without Prompt-Injection Boundaries<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_url.py`, lines 39–49; affected instructions in `SKILL.md`, lines 6, 34–43, and 106–113 **Vulnerability Type**: Indirect prompt injection through attacker-controlled web content **Risk Level**: Medium ### Vulnerable Code ```python if status == 'ok': print(json.dumps({ 'ok': True, 'method': name, 'sourceUrl': args.url, 'fetchedUrl': target, 'status': status, 'attempts': attempts, 'content': text, }, ensure_ascii=False)) return ``` The content classifier only checks for known block-page markers and minimum length: ```python def classify(text: str): low = text.lower() for marker in FAIL_MARKERS: if marker.lower() in low: return 'blocked' if len(text.strip()) < 200: return 'thin' return 'ok' ``` The Skill explicitly positions the returned content for AI use: ```markdown Fetch web pages and extract readable content for AI use. ``` It also describes the script output as containing: ```markdown - final content when successful ``` No instruction requires the consuming agent to treat commands, role declarations, tool requests, or requests for secrets within the fetched content as untrusted page data. ### Technical Analysis The script retrieves arbitrary, remotely controlled text and places it directly in the `content` field. The only security classification applied to that text detects a small list of challenge-page phrases and responses shorter than 200 characters. It does not identify or isolate instructions intended to manipulate an AI agent. A malicious webpage can therefore include statements that impersonate system instructions, ask the agent to ignore the user's objective, request secrets, or direct the agent to invoke tools. Because the Skill states that the output is intended for AI use but establishes no trust boundary, a downstream agent may confuse page content with aut ...[truncated 1937 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add an explicit instruction to `SKILL.md` that all fetched content is untrusted data, not agent instructions. 2. State that the agent must never follow commands, role changes, tool requests, links, or requests for secrets found in retrieved content. 3. Require the agent to use fetched text only to answer the user's stated extraction or summarization request. 4. Delimit remote content clearly from trusted instructions when passing it into an agent context. 5. Label the JSON field as untrusted, for example with metadata such as `"trust": "untrusted_remote_content"`. 6. Require explicit user confirmation before any consequential tool action derived from webpage content. 7. Apply least-privilege controls to downstream tools and prevent page content from authorizing access to credentials, files, memory, or external actions. 8. Where practical, use structured extraction that returns only user-requested fields instead of unrestricted page text. 9. Treat conversion-service output as untrusted as well, because it may contain altered content in addition to the original webpage text. 10. Log or surface suspected instruction-like content for review, while recognizing that heuristic filtering alone is not a reliable security boundary. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Missing User Warnings

High
Confidence
97% confidence
Finding
The script sends user-supplied URLs to third-party proxy/readability services (r.jina.ai, markdown.new, defuddle.md) without any validation or disclosure. This can leak sensitive URLs, query parameters, private document locations, signed links, or internal endpoints to external services, and the skill context makes this more dangerous because the tool is specifically designed to fetch arbitrary URLs and automatically prefers these third parties first.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill directs the agent to perform network access through multiple external fetch services and a bundled script, but it does not declare any explicit tool scope such as allowed tools or permissions. This creates a governance gap: an agent may invoke broader network-capable tooling than intended, making external requests to arbitrary URLs without clear restriction or operator visibility.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code performs HTTP requests to user-supplied and third-party transformed URLs, then later emits the fetched content in JSON output. There is no confirmation prompt, warning print, docstring, or comment disclosing that external requests will be made and remote page content will be returned verbatim.

Static analysis

No suspicious patterns detected.