T09 · Insecure Skill Coding Practices
Error
- Location
- tools/picqer-api.ts:5
- Finding
- Unvalidated Picqer Subdomain Can Redirect API Credentials to an Attacker-Controlled Host## Vulnerability Details **File Location**: `tools/picqer-api.ts`, lines 5–20 **Vulnerability Type**: Credential disclosure through unvalidated URL construction **Risk Level**: High ### Vulnerable Code ```ts const { subdomain, apiKey } = getPicqerConfig(); const url = new URL(`https://${subdomain}.picqer.com/api/v1${path}`); if (searchParams) { Object.entries(searchParams).forEach(([k, v]) => { if (v) url.searchParams.set(k, v); }); } const res = await fetch(url.toString(), { headers: { 'Authorization': `Basic ${Buffer.from(`${apiKey}:`).toString('base64')}`, 'User-Agent': 'FutureFulfillment-Dashboard (internal)' } }); if (!res.ok) { ``` The environment-controlled value originates in `env.ts`, lines 4–10: ```ts const subdomain = process.env.PICQER_SUBDOMAIN; const apiKey = process.env.PICQER_API_KEY; if (!subdomain || !apiKey) { throw new Error('Picqer API not configured. Set PICQER_SUBDOMAIN and PICQER_API_KEY in .env'); } return { subdomain, apiKey }; ``` ### Technical Analysis `PICQER_SUBDOMAIN` is interpolated directly into an absolute URL without validating that it is a single DNS label. URL delimiters such as `/` can therefore change which portion of the generated string is interpreted as the hostname. For example, setting the subdomain to `attacker.example/x` produces: ```text https://attacker.example/x.picqer.com/api/v1/picklists ``` The effective hostname is `attacker.example`, not a host beneath `picqer.com`. The application subsequently attaches the Picqer API key as a Basic Authorization header and sends the request to that effective hostname. Base64 encoding does not protect the credential; it is only an encoding of the API key followed by a colon. TLS protects the request in transit but intentionally delivers it to the attacker-controlled HTTPS endpoint selected by the manipulated URL. ### Attack Path 1. An attacker gains the ...[truncated 1616 chars]
- Remediation
- ## Remediation Suggestions 1. Validate `PICQER_SUBDOMAIN` as exactly one DNS label before using it: ```ts const SUBDOMAIN_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i; if (!SUBDOMAIN_PATTERN.test(subdomain)) { throw new Error('Invalid Picqer subdomain'); } ``` 2. Construct and verify the expected hostname separately: ```ts const hostname = `${subdomain}.picqer.com`; const url = new URL(`/api/v1${path}`, `https://${hostname}`); if ( url.protocol !== 'https:' || url.hostname !== hostname || url.port !== '' ) { throw new Error('Invalid Picqer API URL'); } ``` 3. Prefer an allowlist containing the exact permitted Picqer tenant hostname when the deployment uses a single known tenant. 4. Validate `path` as an internal API path and reject absolute URLs, backslashes, control characters, and unexpected traversal sequences before URL construction. 5. Keep outbound network controls in place so the process can connect only to the approved Picqer hostname where practical. 6. If malicious configuration may already have been used, revoke and rotate `PICQER_API_KEY`, inspect outbound request logs for unexpected hosts, and review Picqer audit logs for unauthorized API activity.
