T09 · Insecure Skill Coding Practices
- Location
src/transcript.js:99- Finding
Unrestricted Caption URL Fetch Enables Server-Side Request Forgery
- Content
View full analysis
Vulnerability Details
File Location:
src/transcript.js:99-111
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: MediumVulnerable Code
js const track = pickBestTrack(tracks); if (!track || !track.baseUrl) { return { ok: false, reason: "no_suitable_caption_track" }; } let xml; try { const response = await fetchImpl(track.baseUrl, { headers: { accept: "application/xml, text/xml" }, }); xml = await response.text(); } catch { return { ok: false, reason: "fetch_captions_failed" }; }Technical Analysis
The Skill extracts
captionTracksfrom remotely retrieved YouTube watch-page HTML. It then passes the selected track'sbaseUrldirectly to the runtime fetch implementation without validating:- The URL scheme
- The destination hostname
- The destination port
- The resolved IP address
- Redirect destinations
Consequently, remotely supplied page content controls the destination of a server-side HTTP request. Tests at
test/index.test.js:1043-1057also demonstrate that caption URLs on an arbitrary non-YouTube hostname are accepted.The expected functionality only requires access to legitimate YouTube caption services. Permitting requests to arbitrary destinations therefore exceeds the minimum network privileges necessary for transcript retrieval.
No credentials or API keys are explicitly attached to the caption request, so the confirmed risk is internal network reachability rather than direct credential disclosure.
Attack Path
- A user or automated workflow invokes the
analyze_videoaction for a supported YouTube video. - The Skill requests the corresponding YouTube watch page.
- A malicious, compromised, intercepted, or custom fetch response supplies a
captionTracksentry whosebaseUrlpoints to an attacker-selected destination. - The Skill selects that caption track and calls
fetchImpl(track.baseUrl)without destination validation. - The host runtime sends a request to the s ...[truncated 994 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse
track.baseUrlwithnew URL()and reject malformed URLs. - Require HTTPS and reject embedded usernames or passwords, fragments, and nonstandard ports.
- Enforce an explicit allowlist of legitimate YouTube caption-service hostnames rather than accepting arbitrary hosts.
- Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 ranges.
- Disable automatic redirects or validate the destination again after every redirect.
- Apply DNS-rebinding protections by ensuring the validated address is the address used for the connection.
- Set strict connection, response, and total-operation timeouts.
- Limit response size before reading the complete body into memory.
- Add negative tests covering:
localhostand loopback addresses- RFC 1918 private addresses
- IPv6 loopback and private ranges
- Cloud metadata addresses
- Non-HTTPS schemes
- Redirects from an allowed host to a prohibited destination
- Arbitrary external domains
- Retain the fixed YouTube Data API destination used by
src/youtube-api.js; the optional API key transmission to that fixed Google endpoint is necessary for the declared enhanced mode and was not identified as unauthorized disclosure.
- Parse
