Back to skill

Security audit

Smart Fetch

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent web-fetching helper, but it allows broad network fetching with weak destination controls that could expose internal services if an untrusted URL is used.

Use this only in environments where broad outbound web access is acceptable, and avoid passing URLs supplied by untrusted users unless you configure a tight allowlist and block internal/private destinations. Enable caching only for content you are comfortable storing locally, and review dependency updates before installation.

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
index.js:221
Finding
Server-Side Request Forgery and Domain-Policy Redirect Bypass<![CDATA[ ## Vulnerability Details **File Location**: `index.js:30-36`, `index.js:82-89`, and `index.js:221-226` **Vulnerability Type**: Server-Side Request Forgery (SSRF) with redirect-based policy bypass **Risk Level**: High ### Vulnerable Code ```js function domainAllowed(hostname) { const host = String(hostname || '').toLowerCase(); if (blocklist.has(host)) return false; // precedence: blocklist > allowlist > default if (allowlist.size > 0) return allowlist.has(host); return true; } ``` ```js async function fetchWithRetry(url, options, retries, debug) { let lastErr; for (let i = 0; i <= retries; i++) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), options.timeoutMs); try { const res = await _fetch(url, { headers: options.headers, signal: controller.signal, redirect: 'follow' }); clearTimeout(timer); return res; ``` ```js try { const u = new URL(url); if (!domainAllowed(u.hostname)) throw new Error(`Domain blocked by policy: ${u.hostname}`); const markdownEnabled = !DISABLE_MARKDOWN_ENV && options.markdown !== false; // env disable has highest priority const timeoutMs = Number(options.timeout || DEFAULT_TIMEOUT_MS); ``` ### Technical Analysis The command accepts a caller-controlled URL and sends a request using the runtime's network privileges. When no allowlist is configured, `domainAllowed()` permits every hostname except exact blocklist entries. It does not reject loopback, private, link-local, multicast, reserved, or cloud metadata addresses. Furthermore, the policy check is performed only against the hostname in the original URL. The request is then issued with `redirect: 'follow'`, allowing the HTTP client to follow redirects automatically without validating each redirect destination. A public or allowlisted host can therefore redirect the request to an internal or explicitly blocklisted destination. Exact hostname comparison is also insufficient to ...[truncated 2316 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict accepted schemes to `https:` and, only where explicitly required, `http:`. Reject all other URL schemes before making a request. 2. Prefer a default-deny domain policy. Require an explicit allowlist for deployments where untrusted users can influence the URL. 3. Resolve the hostname before every connection and reject every address in loopback, private, link-local, multicast, unspecified, reserved, and cloud-metadata ranges for both IPv4 and IPv6. 4. Disable automatic redirect following by using `redirect: 'manual'`. 5. For each redirect: - Resolve the `Location` header relative to the current URL. - Reapply scheme, hostname, port, allowlist, blocklist, and resolved-address checks. - Enforce a small maximum redirect count. - Reject redirects to a less trusted network zone. 6. Ensure the validated IP address is the address actually used for the connection, or use a trusted outbound proxy that enforces destination policy, to mitigate DNS rebinding and time-of-check/time-of-use inconsistencies. 7. Block known metadata destinations explicitly, including link-local metadata addresses, as defense in depth. 8. Consider restricting destination ports to standard web ports or a deployment-specific allowlist. 9. Add automated tests covering direct loopback access, private IPv4 and IPv6 ranges, DNS names resolving to private addresses, public-to-private redirects, blocklisted redirect targets, redirect loops, and DNS rebinding scenarios. 10. Independently enforce a streaming response-size limit and abort oversized downloads. The current `maxBytes` option is applied only after the entire response has been buffered and therefore does not prevent memory or bandwidth exhaustion. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • 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
Findings (12)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
{ key: 'contains_download_and_execute_lure', re: /(download and run|下载安装并运行|粘贴并执行)/i },
    { key: 'contains_api_key_request', re: /(paste.*api key|share your api key|提供你的api key|输入你的token)/i }
  ];
  return rules.filter(r => r.re.test(s)).map(r => r.key);
}

function routeAdvice(pathName, warnings) {
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill describes network access, environment-controlled behavior, and execution via a local Node CLI, but it does not declare any explicit tool scope such as allowed tools or permissions. That creates an overbroad trust boundary: an agent may invoke the skill with more shell/env/network capability than reviewers expect, increasing the chance of unsafe fetches, policy bypass, or misuse of inherited environment data.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script persists fetched content and metadata to a cache directory via `writeCache(cacheDir, ck, result)`, which can store remote page contents under the user's home directory. Although caching is implemented as a feature, there is no confirmation prompt or user-facing warning in output/help text that fetched data will be written to local disk by default when cache TTL is enabled.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The safety-flag detection logic includes specific Chinese phrases alongside English ones, but the skill does not indicate language selection, user opt-in, or a justified locale-specific scope. This creates uneven language handling baked into natural-language policy logic.

Known Vulnerable Dependency: @mozilla/readability==0.5.0 — 1 advisory(ies): CVE-2025-2792 (@mozilla/readability Denial of Service through Regex)

Low
Category
Supply Chain
Confidence
89% confidence
Finding
The lockfile pins @mozilla/readability to 0.5.0, which is reported vulnerable to a regex-based denial of service. In a web-fetching/scraping skill that parses attacker-controlled HTML, this dependency is directly exposed to untrusted content, so a crafted page could cause excessive CPU use or processing delays.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"smart-fetch": "./index.js"
  },
  "dependencies": {
    "jsdom": "^24.0.0",
    "turndown": "^7.1.3",
    "@mozilla/readability": "^0.5.0",
    "commander": "^12.0.0"
Confidence
97% confidence
Finding
The dependency is version-ranged with a caret (^24.0.0), which allows automatic installation of newer minor/patch releases. This is a real supply-chain risk because builds are not fully reproducible and a compromised or breaking upstream release could be pulled in without explicit review, though the impact here is typically limited compared with direct code flaws.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "jsdom": "^24.0.0",
    "turndown": "^7.1.3",
    "@mozilla/readability": "^0.5.0",
    "commander": "^12.0.0"
  }
Confidence
97% confidence
Finding
The dependency uses a caret range (^7.1.3), so installs may resolve to different package contents over time. That creates a genuine but low-severity supply-chain exposure through non-deterministic builds and unreviewed upstream changes rather than an immediate exploit in this file itself.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"dependencies": {
    "jsdom": "^24.0.0",
    "turndown": "^7.1.3",
    "@mozilla/readability": "^0.5.0",
    "commander": "^12.0.0"
  }
}
Confidence
98% confidence
Finding
Using ^0.5.0 for @mozilla/readability permits automatic changes within the allowed semver range, weakening reproducibility and dependency control. In a tool that processes untrusted web content, dependency hygiene matters more because parser libraries are part of the attack surface.

Known Vulnerable Dependency: @mozilla/readability==0.5.0 — 1 advisory(ies): CVE-2025-2792 (@mozilla/readability Denial of Service through Regex)

Low
Category
Supply Chain
Confidence
99% confidence
Finding
@mozilla/readability 0.5.0 is flagged with a known denial-of-service issue via regex processing. In the context of this skill, which fetches and parses attacker-controlled web pages for LLM ingestion, a malicious page could trigger excessive CPU consumption or hangs during content extraction, making this more dangerous than in a purely local trusted-input tool.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"jsdom": "^24.0.0",
    "turndown": "^7.1.3",
    "@mozilla/readability": "^0.5.0",
    "commander": "^12.0.0"
  }
}
Confidence
97% confidence
Finding
The commander package is specified with a caret version (^12.0.0), allowing future upstream changes to be pulled during install. This is a legitimate low-severity supply-chain concern because it can introduce unreviewed behavior or vulnerabilities even if no direct flaw is visible here.