Back to skill

Security audit

Ddg Search Fetch

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but its arbitrary URL fetching is under-scoped and could reach internal services from the agent environment.

Install only if you are comfortable with the agent making outbound web requests. Avoid using it for sensitive search terms, private URLs, localhost, intranet hosts, cloud metadata addresses, or URLs containing tokens. Prefer running it in a network-restricted environment and remove or pin the unnecessary dependency instruction before production 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ddg_fetch.py:78
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ddg_fetch.py`, lines 78-103 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python # Validate URL parsed = urllib.parse.urlparse(url) if not parsed.scheme: # Add https if missing url = 'https://' + url parsed = urllib.parse.urlparse(url) if not parsed.netloc: result["error"] = "Invalid URL" return result # Build request req = urllib.request.Request( url, headers={ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.0 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7', 'Accept-Encoding': 'gzip, deflate', 'DNT': '1', 'Connection': 'keep-alive', } ) # Make request with urllib.request.urlopen(req, timeout=timeout) as response: ``` ### Technical Analysis The URL validation only verifies that the parsed URL contains a network location. It does not: - Restrict the scheme to `http` or `https`. - Reject loopback addresses such as `127.0.0.1` or `::1`. - Reject private, link-local, reserved, or unspecified IP address ranges. - Block cloud metadata endpoints such as `169.254.169.254`. - Resolve hostnames and validate their resulting IP addresses. - Validate redirect destinations before following them. Python's `urllib.request.urlopen` follows HTTP redirects by default. Consequently, validating only the initial hostname would remain insufficient because a public endpoint could redirect the request to an internal address. ### Attack Path 1. An attacker supplies a URL through the Skill's documented fetch operation. 2. The URL identifies an internal service, loopback interface, private network host, or cloud metadata endpoint. 3. The parser accepts the URL because it has a scheme and network location. 4. `urllib. ...[truncated 1018 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only explicit `http` and `https` schemes. 2. Reject URLs containing embedded credentials or malformed hostnames. 3. Resolve the hostname before connecting and inspect every returned IPv4 and IPv6 address. 4. Reject loopback, private, link-local, multicast, reserved, and unspecified addresses using Python's `ipaddress` module. 5. Explicitly deny cloud metadata addresses and environment-specific internal domains. 6. Disable automatic redirects or implement a redirect handler that repeats the full scheme, hostname, and resolved-address validation for every destination. 7. Protect against DNS rebinding by connecting to a previously validated address while preserving the intended HTTP host and TLS hostname verification. 8. Consider using an outbound proxy or network policy that prevents the Skill process from reaching internal networks. 9. Apply an allowlist of trusted domains when arbitrary Internet fetching is not required. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ddg_fetch.py:103
Finding
Unbounded Response Reading and Gzip Decompression Can Exhaust Memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ddg_fetch.py`, lines 103-117 **Vulnerability Type**: Uncontrolled Resource Consumption **Risk Level**: Medium ### Vulnerable Code ```python with urllib.request.urlopen(req, timeout=timeout) as response: result["status_code"] = response.status # Get content encoding content_encoding = response.headers.get('Content-Encoding', '') # Read content content = response.read() # Decode based on encoding if content_encoding == 'gzip': import gzip content = gzip.decompress(content) html = content.decode('utf-8', errors='ignore') ``` ### Technical Analysis `response.read()` loads the entire response body into memory without a byte limit. If the response is gzip-encoded, `gzip.decompress()` then expands the complete compressed payload into another in-memory object without enforcing a decompressed-size limit. The later 10,000-character text limit does not mitigate this issue because it is applied only after the full response has already been downloaded, decompressed, decoded, and processed. The request timeout limits elapsed socket operations but does not impose a maximum response size. An attacker-controlled server can therefore return an oversized document or a small gzip payload with a very high expansion ratio. ### Attack Path 1. An attacker hosts a very large response or a gzip-compression bomb. 2. The attacker asks the Skill to fetch the malicious URL. 3. The script reads the entire response into memory with `response.read()`. 4. For gzip content, the script allocates additional memory while decompressing the complete payload. 5. Memory consumption grows until the process becomes unresponsive, is terminated, or causes resource pressure on the wider Agent environment. ### Impact Assessment Exploitation can cause denial of service against the Skill process or its hosting Agent. In a shared environment, excessive memory consumption may also degrade o ...[truncated 169 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Read the response incrementally in fixed-size chunks. 2. Enforce a strict maximum compressed response size and stop reading when that limit is exceeded. 3. Reject a declared `Content-Length` that exceeds the configured maximum, while still enforcing the streaming limit because the header may be absent or dishonest. 4. Use streaming gzip decompression and independently limit the total decompressed bytes. 5. Set reasonable connection and read timeouts. 6. Reject unsupported content encodings and content types when only HTML is expected. 7. Avoid retaining multiple full-size copies of the response in compressed, decompressed, decoded, and extracted forms. 8. Return a controlled error when any resource limit is reached. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:10
Finding
Unpinned and Unnecessary Third-Party Package Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 10-15; duplicated in `README.md`, lines 12-18 **Vulnerability Type**: Unsafe Dependency Installation Guidance **Risk Level**: Low ### Vulnerable Code ```markdown ## Prerequisites 需要安装依赖: ```bash pip3 install duckduckgo-search ``` ``` The same installation command appears in `README.md`: ```bash pip3 install duckduckgo-search ``` ### Technical Analysis The documentation instructs users to install the latest package version available under the `duckduckgo-search` name from the configured Python package index. No version constraint, lock file, integrity hash, or reviewed artifact is supplied. The bundled scripts use Python standard-library networking and parsing functionality and do not import `duckduckgo-search`. The documented installation therefore adds supply-chain exposure without being required by the reviewed implementation. An unpinned dependency can change after this Skill version has been audited. Package installation may execute build backend or installation-related code, and the resulting environment is not reproducible. ### Attack Path 1. A user follows the documented prerequisite. 2. `pip` resolves whichever package version is current on the configured package index. 3. Package metadata, build dependencies, and package code are obtained outside the audited project. 4. A compromised package release, package-index configuration, or transitive build dependency may execute code during installation or introduce vulnerable runtime components. ### Impact Assessment The package installation runs with the privileges of the user invoking `pip`. If installation is performed inside a privileged Agent image or administrative environment, a compromised dependency could affect that environment with equivalent privileges. No evidence was found that the currently named package is malicious; the confirmed issue is the unnecessary, unpinned, and non-reproducible installation instruction ...[truncated 7 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `pip3 install duckduckgo-search` prerequisite because the reviewed scripts do not import or require that package. 2. If the package becomes necessary, pin an audited version using an exact version constraint. 3. Record dependencies in a lock file and require cryptographic hashes, such as through `pip --require-hashes`. 4. Review and pin build dependencies as well as direct runtime dependencies. 5. Install dependencies in an isolated virtual environment under a non-privileged account. 6. Use a controlled package repository or approved artifact mirror for production deployments. 7. Add automated dependency and provenance scanning to the release process. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description claims two major functions: web search via DuckDuckGo and URL fetching/content extraction. This code chunk implements only the second function. It accepts a URL argument, issues an HTTP request, parses HTML, extracts readable text, and returns metadata. There is no logic to query DuckDuckGo, construct search requests, parse search result pages, or return a list of search results. Therefore the declared description materially overstates the code’s actual behavior, making it a description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The implemented script matches the search portion of the description: it queries DuckDuckGo without an API key, returns structured search results with title, URL, and snippet, and includes a fallback method using curl. However, the declared purpose also claims support for 'URL fetching' and extracting readable content from web pages, with triggers like 'fetch url' and 'get page content'. No such functionality exists in the supplied code. This is a material description-behavior mismatch because the declared capability includes a second major function that is absent from the implementation.

Context-Inappropriate Capability

High
Confidence
93% confidence
Finding
A search skill reasonably needs outbound HTTP requests, but invoking an external system binary is a materially broader capability than necessary for searching or fetching page content. This introduces command-execution capability unrelated to the manifest's stated purpose of simple web search without API keys.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README describes web search and page fetching but does not warn that user queries and target URLs are transmitted to external network services. In an agent setting, this omission can mislead operators and users into exposing sensitive prompts, internal hostnames, tokens in URLs, or other confidential data to third parties.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The documented trigger phrases are broad natural-language patterns such as 'search for' and 'look up', which are common in ordinary conversation and can cause unintended invocation of this skill. In an agent environment, that can silently send user queries or referenced URLs to external services, creating privacy and policy-bypass risk through accidental activation rather than explicit consent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documents executable Python scripts that perform web search/fetch operations and are invoked through shell commands, but the manifest does not declare any tool scope such as permissions or allowed-tools. In an agent ecosystem, undeclared network and shell capability reduces policy enforcement and review visibility, increasing the chance of unintended command execution or outbound requests.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The description includes broad trigger phrases like 'search for', 'look up', and 'get page content', which can cause the skill to activate in many ordinary conversations. In an agent setting, over-broad invocation can lead to unexpected network access, external content retrieval, and shell/script execution without sufficiently specific user intent.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation advertises web search and URL fetching but does not warn that using the skill sends requests to external services and retrieves untrusted remote content. Users and orchestrators may therefore invoke it without understanding privacy, tracking, or hostile-content exposure risks.

Description-Behavior Mismatch

Medium
Confidence
84% confidence
Finding
The manifest describes a web search and URL-fetching skill, and network access to DuckDuckGo is expected. However, this file's documented behavior is specifically about DuckDuckGo search, while the implementation adds process execution via an external curl command as an additional operational capability not reflected in the skill description.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
url
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=25)
        html = result.stdout
        
        if result.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The code hard-codes 'Accept-Language: en-US,en;q=0.9', which imposes a specific language/locale on all requests. This is a natural-language policy concern because the skill does not offer user opt-in or any documented reason for restricting locale behavior.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The primary descriptive text is presented in Chinese with no indication that other languages are available or that the skill is intentionally region-specific. This can violate language or locale policy when a skill imposes a language without user opt-in or justification.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
Several headings and instructions switch to Chinese (for example, installation and feature descriptions) even though the rest of the document is in English. This imposes a language choice on users without opt-in and may violate language/locale policy expectations.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The code hard-codes an Accept-Language header of "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7", which imposes a specific locale preference on all requests. This is a natural-language policy concern because users are not given any opt-in or configuration choice for the language/locale the skill presents to external sites.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The script falls back to running curl through subprocess.run, which is a subprocess execution path covered by the warning requirement for code files. Although the module docstring mentions a fallback, there is no visible confirmation, log, or CLI warning that an external command may be executed during operation.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This code sends the user's search query to DuckDuckGo over HTTP(S) via urllib, which is a network operation that transmits user data off-system. While the script's purpose is search, the file provides no explicit user-facing notice in the argument help, output, or runtime messaging that the query will be sent to an external service.

Static analysis

No suspicious patterns detected.