T09 · Insecure Skill Coding Practices
Warning
- Location
- references/parse-tickets.mjs:251
- Finding
- Unrestricted HTTP Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `references/parse-tickets.mjs:251-258` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through unrestricted URL fetching **Risk Level**: Medium ### Vulnerable Code ```js if (/^https?:\/\//i.test(src)) { const res = await fetch(src, { redirect: 'follow' }); if (!res.ok) { process.stderr.write(`accesso: HTTP ${res.status} fetching ticket page\n`); process.exit(4); } return { html: await res.text(), url: res.url || src }; } ``` ### Technical Analysis The Skill is declared to process ticket pages hosted under Accesso media-engine domains, but `readSource()` accepts any URL beginning with `http://` or `https://`. It does not validate: - The destination hostname against the expected Accesso service. - Whether the destination is a loopback, private, link-local, or reserved address. - Nonstandard destination ports. - DNS results that resolve to internal addresses. - Redirect destinations. - HTTPS-to-HTTP redirect downgrades. The use of `redirect: 'follow'` is especially significant because an initially acceptable external URL can redirect to an internal destination. Validation applied only before `fetch()` would consequently be insufficient unless redirects are handled and checked individually. This behavior exceeds the minimum privileges needed for the declared functionality. Reading Accesso tickets requires network access to the applicable `media-engine.<region>.accessoticketing.com` host, but it does not require arbitrary server-side HTTP access. The fetched response is parsed locally rather than returned verbatim, which limits direct response disclosure. Nevertheless, the primitive can issue GET requests from the Agent host, expose status-dependent behavior, and potentially surface content if an internal response resembles the ticket markup expected by the parser. ### Attack Path 1. An attacker supplies an Agent user or workflow with a purported ticket URL. 2. The URL is one ...[truncated 1856 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Require HTTPS** - Reject plaintext HTTP URLs. - Reject redirects that downgrade from HTTPS to HTTP. 2. **Enforce an explicit hostname allowlist** - Permit only the Accesso media-engine hostname pattern required by the Skill. - Compare normalized URL hostnames rather than using substring or suffix checks that can be bypassed by names such as `accessoticketing.com.attacker.example`. - If regions are known, prefer an explicit set of approved hosts. 3. **Validate every redirect** - Set `redirect: 'manual'`. - Resolve each `Location` header against the current URL. - Reapply scheme, hostname, port, and IP-address validation before issuing the next request. - Set a small maximum redirect count. 4. **Block internal network destinations** - Resolve the hostname before connecting. - Reject IPv4 and IPv6 loopback, private, link-local, multicast, unspecified, and reserved ranges. - Protect against alternate IP representations and IPv4-mapped IPv6 addresses. - Mitigate DNS rebinding by ensuring that the validated address is the address used for the connection. 5. **Restrict ports** - Permit only TCP port 443 unless another port is explicitly required and documented. 6. **Apply runtime containment** - Use outbound firewall or sandbox rules that permit connections only to approved Accesso endpoints. - Block access to cloud metadata addresses and internal management networks independently of application validation. 7. **Protect ticket bearer URLs** - Continue treating `oToken` and `cToken` values as credentials. - Prefer stdin or another protected input mechanism over command-line arguments, which may be visible in process listings or retained in shell history. - Redact query strings from diagnostics and logs. ]]>
