T05 · Unauthorized Access and Privilege Escalation
- Location
src/commands/job.ts:544- Finding
Attacker-Controlled Schema URI Enables Server-Side Request Forgery
- Content
View full analysis
{ let schemaPayload: unknown; if (schemaUri.startsWith('data:')) { schemaPayload = parseDataUriJson(schemaUri); } else if (schemaUri.startsWith('http://') || schemaUri.startsWith('https://')) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 30_000); try { const response = await fetch(schemaUri, { signal: controller.signal }); if (!response.ok) { throw new Error(`Failed to fetch requirements schema URI (${response.status} ${response.statusText})`); } const buf = await response.arrayBuffer(); if (buf.byteLength > 1_048_576) { throw new Error(`Schema too large (${buf.byteLength} bytes). Limit is 1MB`); } schemaPayload = JSON.parse(new TextDecoder().decode(buf)); } finally { clearTimeout(timeoutId); } } else if (schemaUri.trim().startsWith('{')) { schemaPayload = JSON.parse(schemaUri); } else { return null; } if (!isOfferingSchema(schemaPayload)) { throw new Error('requirementsSchemaURI did not resolve to a valid OfferingSchema document'); } return schemaPayload; } ``` ### Technical Analysis The `requirementsSchemaURI` value comes from marketplace offering data and is therefore controlled by the offering publisher. When a buyer creates a job with requirements, the CLI passes that value directly to `fetch()`. The implementation only verifies that the URI starts with `http://` or `https://`. It does not: - Reject loopback, privat ...[truncated 2874 chars]- Remediation
View remediation
