{"record":{"id":"baf2db1f05087225","repo":"openclaw/openclaw","slug":"invalid-url-supplied-to-sandbox-http-request","errorCode":null,"errorMessage":"Invalid URL supplied to sandbox http/request","messagePattern":"Invalid URL supplied to sandbox http/request","errorType":"validation","errorClass":"SsrFBlockedError","httpStatus":null,"severity":"error","filePath":"extensions/codex/src/app-server/sandbox-exec-server/http.ts","lineNumber":64,"sourceCode":"  });\n  return result;\n}\n\ntype SandboxHttpRequest = {\n  method: string;\n  url: string;\n  headers: HttpHeader[];\n  bodyBase64?: string;\n  timeoutMs?: number;\n  streamResponse: boolean;\n};\n\nfunction assertSandboxHttpRequestTargetAllowed(url: string): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new SsrFBlockedError(\"Invalid URL supplied to sandbox http/request\");\n  }\n  if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n    throw new SsrFBlockedError(\n      `Blocked non-HTTP(S) protocol in sandbox http/request: ${parsed.protocol}`,\n    );\n  }\n  if (isBlockedHostnameOrIp(parsed.hostname)) {\n    throw new SsrFBlockedError(\n      `Blocked hostname or private/internal IP in sandbox http/request: ${parsed.hostname}`,\n    );\n  }\n}\n\nasync function runSandboxHttpRequest(\n  execServer: OpenClawExecServer,\n  params: SandboxHttpRequest,\n): Promise<JsonObject & { status: number; headers: HttpHeader[]; bodyBase64: string }> {\n  const backend = requireBackend(execServer);","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/extensions/codex/src/app-server/sandbox-exec-server/http.ts#L46-L82","documentation":"assertSandboxHttpRequestTargetAllowed wraps URL parsing in try/catch; if new URL(url) throws, the function throws SsrFBlockedError with this message. It is the first gate in the sandbox HTTP request path, run before protocol, hostname, or SSRF checks.","triggerScenarios":"An http/request JSON-RPC call whose url field is not parseable as a URL: empty string, missing scheme, unbalanced brackets, stray characters, or a value that is technically a string but not a valid absolute URL (e.g. 'example.com', '://x', '[::1').","commonSituations":"Agent sending a bare hostname without scheme; URL built from untrusted text that failed sanitization; copy-paste that dropped 'https://'; template strings that left the scheme empty.","solutions":["Provide a fully-qualified URL including scheme, e.g. 'https://example.com/path'","Validate with new URL(url) in your caller before issuing http/request","Prepend 'https://' when the input lacks a scheme, then re-validate"],"exampleFix":"// before\nawait execServer.httpRequest({ url: 'api.example.com/v1', method: 'GET' });\n\n// after\nawait execServer.httpRequest({ url: 'https://api.example.com/v1', method: 'GET' });","handlingStrategy":"validation","validationCode":"function assertValidSandboxUrl(url: string): void {\n  try {\n    new URL(url);\n  } catch {\n    throw new Error('Invalid URL supplied to sandbox http/request');\n  }\n}","typeGuard":"function isParsableUrl(url: unknown): url is string {\n  if (typeof url !== 'string') return false;\n  try { new URL(url); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  await execServer.httpRequest({ url, method: 'GET' });\n} catch (error) {\n  if (error instanceof Error && /Invalid URL/.test(error.message)) {\n    // prepend 'https://' and retry, or reject the input\n  } else throw error;\n}","preventionTips":["Always include the scheme (http:// or https://) in URLs","Pre-validate URLs with new URL() before issuing http/request","Sanitize URL input from untrusted sources before dispatch"],"tags":["network","http","sandbox","codex","validation"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}