T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ns-api.mjs:28
- Finding
- NS Subscription Key May Be Disclosed Across HTTP Redirects## Vulnerability Details **File Location**: `scripts/ns-api.mjs`, lines 28–39 **Vulnerability Type**: Credential exposure through unvalidated redirects **Risk Level**: Medium ```js export async function nsFetch(url, { subscriptionKey, headers = {}, ...opts } = {}) { const u = assertAllowlistedUrl(url); const res = await fetch(u, { ...opts, headers: { 'Ocp-Apim-Subscription-Key': subscriptionKey, 'Accept': 'application/json', ...headers, }, }); return res; } ``` ### Technical Analysis `assertAllowlistedUrl()` validates only the initial request URL. It requires HTTPS and restricts the hostname to `gateway.apiportal.ns.nl`. However, `fetch()` follows HTTP redirects by default, and the redirect destination is not passed through the URL validation function. The request includes the sensitive `Ocp-Apim-Subscription-Key` custom header. Unlike certain standard credential headers that implementations may remove during cross-origin redirects, this custom header cannot safely be assumed to be stripped. Therefore, a redirect to another origin may cause the subscription key to be transmitted outside the documented host allowlist. This behavior also makes the guarantee in `SECURITY.md`—that only the NS API gateway receives requests—stronger than the protection actually enforced by the implementation. ### Attack Path 1. A legitimate script invokes `nsFetch()` with the user's NS subscription key. 2. The allowlisted NS gateway, or an endpoint under that gateway, returns an HTTP redirect. 3. Exploitation requires the trusted gateway or its response path to be compromised, maliciously configured, or otherwise capable of redirecting to an attacker-controlled HTTPS origin. 4. Because redirect handling remains at the default `follow` setting, `fetch()` follows the redirect without invoking `assertAllowlistedUrl()` again. 5. The custom `Ocp-Apim-Subscription-Key` header may be forwarde ...[truncated 647 chars]
- Remediation
- ## Remediation Suggestions - Set `redirect: 'manual'` in the initial `fetch()` request and reject redirects unless they are explicitly required. - If redirects must be supported, resolve each `Location` header against the current URL and validate every destination with the same HTTPS and exact-host allowlist before making another request. - Never forward `Ocp-Apim-Subscription-Key` when the redirect changes the origin. - Impose a small redirect limit to prevent loops and redirect-based resource exhaustion. - Prevent callers from overriding the redirect policy through `opts`; apply the security-controlled option after spreading caller options. - Add automated tests covering redirects to non-allowlisted hosts, non-HTTPS destinations, malformed locations, redirect loops, and same-host redirects. - Update `SECURITY.md` so its egress guarantee precisely reflects the implemented redirect policy.
