T09 · Insecure Skill Coding Practices
- Location
content.js:5- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery in content.js
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This search skill does what a web-search tool is expected to do, but it is under-disclosed because it scrapes Brave pages instead of using the advertised API and can fetch arbitrary URLs from the agent's network context.
Install only if you are comfortable with a skill that performs live web requests, scrapes Brave's public results page rather than using the advertised Brave API, and can fetch arbitrary URLs from the agent's network. Avoid using it with confidential search terms or URLs, and run it in an environment where outbound requests cannot reach private services or metadata endpoints.
content.js:5Unrestricted URL Fetching Enables Server-Side Request Forgery in content.js
search.js:106Unvalidated Search Result Destinations Enable Indirect Server-Side Request Forgery
Using website scraping instead of the declared Brave Search API changes the trust and security model: scraping often requires broader arbitrary HTTP fetching and may reach untrusted third-party content. Combined with undeclared permissions, this creates a larger-than-advertised attack surface and increases the chance of data exfiltration, unsafe content ingestion, or policy bypass.
Using website scraping instead of the declared Brave Search API changes the trust and security model: scraping often requires broader arbitrary HTTP fetching and may reach untrusted third-party content. Combined with undeclared permissions, this creates a larger-than-advertised attack surface and increases the chance of data exfiltration, unsafe content ingestion, or policy bypass.
Referenced artifact was not completely inspected
./search.js "query" # Basic search (5 results)
Referenced artifact was not completely inspected
./search.js "query" # Basic search (5 results)
Referenced artifact was not completely inspected
./search.js "query" # Basic search (5 results)
Referenced artifact was not completely inspected
./search.js "query" # Basic search (5 results)
The lockfile pins jsdom's transitive dependency ws to version 8.19.0, and the supplied advisories indicate this version is affected by memory disclosure and memory-exhaustion denial of service issues. Even though this skill is a web search/content extraction tool and may not explicitly expose WebSocket features, bundling a known vulnerable library is still risky because jsdom can bring ws into reachable runtime paths or future code changes may use it unintentionally.
The skill documentation declares functionality that clearly requires outbound network access, but it does not declare any explicit tool scope or permissions. This weakens policy enforcement and reviewability, making it easier for a skill to perform external requests without clear operator awareness or least-privilege constraints.
The description says to use the skill for 'searching documentation, facts, or any web content.' The phrase 'any web content' is very broad and lacks constraints or negative examples, which could cause unintended invocation for general web-related requests.
The skill metadata claims Brave Search API usage, but the implementation actually scrapes Brave's public HTML results page using browser-like headers. This is a supply-chain trust and transparency issue: operators may approve the skill believing it uses a stable API with known terms, data handling, and rate controls, while it really depends on brittle scraping behavior that can bypass expectations and fail unpredictably.
The skill sends the user's search query to Brave and, with --content, fetches arbitrary third-party pages from returned links. This creates privacy and security exposure because user-supplied queries may contain sensitive internal terms, and content fetching expands network disclosure to external sites without explicit warning, allowlisting, or consent.
The request hard-codes an Accept-Language header of en-US,en;q=0.9, which imposes an English/US locale preference regardless of the user's actual language settings. This is a natural-language policy concern because the file does not offer a user choice or document a justified region-specific constraint.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"author": "Mario Zechner",
"license": "MIT",
"dependencies": {
"@mozilla/readability": "^0.6.0",
"jsdom": "^27.0.1",
"turndown": "^7.2.2",
"turndown-plugin-gfm": "^1.0.2"
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"license": "MIT",
"dependencies": {
"@mozilla/readability": "^0.6.0",
"jsdom": "^27.0.1",
"turndown": "^7.2.2",
"turndown-plugin-gfm": "^1.0.2"
}
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"dependencies": {
"@mozilla/readability": "^0.6.0",
"jsdom": "^27.0.1",
"turndown": "^7.2.2",
"turndown-plugin-gfm": "^1.0.2"
}
}
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"@mozilla/readability": "^0.6.0",
"jsdom": "^27.0.1",
"turndown": "^7.2.2",
"turndown-plugin-gfm": "^1.0.2"
}
}
The code hard-codes Accept-Language to en-US,en;q=0.9, which imposes a specific language/locale preference in outbound requests. There is no option for the user to choose a different locale or any documented justification that this tool must be English-only.
No suspicious patterns detected.