T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/briefing.mjs:6
- Finding
- Unrestricted Redirect Following and Unbounded HTTP Response Buffering<![CDATA[ ## Vulnerability Details **File Location**: `scripts/briefing.mjs`, lines 6–47 **Vulnerability Type**: Unrestricted redirects and resource exhaustion **Risk Level**: Medium ```js function fetchText(url, { timeoutMs = 15000 } = {}) { return new Promise((resolve, reject) => { const u = new URL(url); const req = https.request( { method: 'GET', hostname: u.hostname, path: u.pathname + u.search, headers: { 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123 Safari/537.36', accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.7,en;q=0.6' } }, (res) => { if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { // follow redirect (handle relative Location) const nextUrl = new URL(res.headers.location, url).toString(); resolve(fetchText(nextUrl, { timeoutMs })); res.resume(); return; } if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) { const code = res.statusCode; res.resume(); reject(new Error(`HTTP ${code} for ${url}`)); return; } res.setEncoding('utf8'); let data = ''; res.on('data', (c) => (data += c)); res.on('end', () => resolve(data)); } ); req.on('error', reject); req.setTimeout(timeoutMs, () => { req.destroy(new Error(`Timeout after ${timeoutMs}ms for ${url}`)); }); req.end(); }); } ``` ### Technical Analysis The HTTP helper follows every redirect recursively without a redirect counter, destination-host allowlist, protocol validation, or private-address restriction. Consequently, a redirected request is not constrained to the expected Daum domains. The helper also concate ...[truncated 1633 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Add a strict redirect limit, such as three to five hops. - Permit only the `https:` protocol and explicitly reject all other protocols. - Allowlist the expected destination hosts, such as `www.daum.net` and `search.daum.net`. - Resolve destination addresses and reject loopback, private, link-local, multicast, and other reserved ranges when arbitrary redirects are not required. - Enforce a maximum response size while processing chunks and destroy the request once the limit is exceeded. - Validate `Content-Length` before reading when it is present, while retaining the streaming limit because that header is not always trustworthy. - Apply an overall operation deadline across the entire redirect chain rather than resetting the effective time budget for every request. - Prefer an iterative redirect loop over recursive promise chaining so redirect state and cumulative limits are explicit. ]]>
