T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/fetch-post.ts:110
- Finding
- Server-Side Request Forgery Through Insufficient Social Platform URL Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-post.ts:110-124` and `scripts/lib/metadata-fetcher.ts:191-221` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```ts // scripts/fetch-post.ts:110-124 // Detect platform const isInstagram = validUrl.includes("instagram.com"); const isTikTok = validUrl.includes("tiktok.com") || validUrl.includes("vm.tiktok.com"); if (!isInstagram && !isTikTok) { console.error(JSON.stringify({ error: "Unsupported platform. Supports Instagram and TikTok." })); process.exit(1); } const startTime = Date.now(); const metadata = isInstagram ? await fetcher.getInstagramPost(validUrl) : await fetcher.getTiktokVideo(validUrl); ``` ```ts // scripts/lib/metadata-fetcher.ts:191-221 private async getInstagramPostFromOgTags(url: string): Promise<PostMetadata | null> { try { const resp = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.9", "Accept-Encoding": "gzip, deflate, br", "Cache-Control": "no-cache", Pragma: "no-cache", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", }, signal: AbortSignal.timeout(TIMEOUTS.ogTags), redirect: "follow", }); if (!resp.ok) { console.error("[MetadataFetcher] Failed to fetch Instagram page:", resp.status); return null; } const html = await resp.text(); const ogTags = extractOgTags(html); ``` ### Technical Analysis The platform check uses substring matching rather than parsing and validating the URL hostname. Any URL containing the text `instagram.com` or `tiktok.com` can pass, even when its actua ...[truncated 2424 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse input with `new URL()` before platform classification. 2. Require the `https:` protocol. 3. Compare normalized hostnames rather than using substring matching: - Permit `instagram.com` and hostnames ending in `.instagram.com`. - Permit `tiktok.com` and hostnames ending in `.tiktok.com`. 4. Reject URLs containing embedded credentials or nonstandard ports unless explicitly required. 5. Resolve the hostname before connecting and reject: - Loopback addresses. - RFC 1918 private addresses. - Link-local addresses. - Carrier-grade NAT ranges. - Multicast, unspecified, and other reserved addresses. - IPv4-mapped IPv6 variants of prohibited addresses. 6. Disable automatic redirects or validate the scheme, hostname, and resolved address at every redirect hop. 7. Apply the same centralized validator to Apify inputs, direct Open Graph requests, TikTok oEmbed inputs, and media URLs. 8. Add regression tests for deceptive hostnames, user-info syntax, encoded IP addresses, IPv6 addresses, DNS rebinding, and redirects to private networks. ]]>
