{"record":{"id":"bbcd462b8a8e4218","repo":"heygen-com/hyperframes","slug":"freeze-failed-refusing-non-figma-url-url-http","errorCode":null,"errorMessage":"freeze failed: refusing non-figma url ${url} (https + figma hosts only)","messagePattern":"freeze failed: refusing non-figma url (.+?) \\(https \\+ figma hosts only\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/figma/freeze.ts","lineNumber":52,"sourceCode":" * Only figma-owned hosts may be frozen from a URL — render/CDN responses\n * come from figma.com subdomains or figma's S3 buckets. Blocks SSRF via a\n * crafted manifest/config URL (metadata endpoints, internal services).\n */\nexport function isAllowedFreezeUrl(url: string): boolean {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    return false;\n  }\n  if (parsed.protocol !== \"https:\") return false;\n  const host = parsed.hostname;\n  return host === \"figma.com\" || host.endsWith(\".figma.com\") || host.endsWith(\".amazonaws.com\");\n}\n\nexport async function freezeUrl(url: string, destPath: string): Promise<number> {\n  if (!isAllowedFreezeUrl(url))\n    throw new Error(`freeze failed: refusing non-figma url ${url} (https + figma hosts only)`);\n  const res = await fetch(url);\n  if (!res.ok) throw new Error(`freeze failed: HTTP ${res.status}`);\n  const declared = Number(res.headers.get(\"content-length\") ?? 0);\n  if (exceedsFreezeCap(declared))\n    throw new Error(`freeze failed: content-length ${declared} exceeds ${MAX_FREEZE_BYTES} cap`);\n  return freezeBytes(new Uint8Array(await res.arrayBuffer()), destPath);\n}\n\nexport function freezeLocalFile(srcPath: string, destPath: string): void {\n  const size = statSync(srcPath).size;\n  if (exceedsFreezeCap(size))\n    throw new Error(`freeze failed: ${size} bytes exceeds ${MAX_FREEZE_BYTES} cap`);\n  mkdirSync(dirname(destPath), { recursive: true });\n  copyFileSync(srcPath, destPath);\n}\n","sourceCodeStart":34,"sourceCodeEnd":68,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/core/src/figma/freeze.ts#L34-L68","documentation":"Thrown by freezeUrl when isAllowedFreezeUrl(url) returns false. The allowlist requires https AND a host that is exactly 'figma.com', ends with '.figma.com', or ends with '.amazonaws.com' (figma's S3 CDN). This is an SSRF guard: a crafted manifest or config URL pointing at internal metadata endpoints (169.254.169.254, localhost services, etc.) must not be fetched and written to disk by the freeze step. Non-https and non-figma hosts are both rejected.","triggerScenarios":"Passing a http:// URL; an http://localhost internal service URL; an https://evil.com URL planted in a manifest; an https:// internal metadata endpoint; a URL whose host is a bare IP (never matches the allowlist).","commonSituations":"A figma file's image fill URL was rewritten by a corporate proxy to a non-figma host; a dev pointing freezeUrl at a locally-hosted mirror for testing; a maliciously crafted figma manifest (the threat model this guard exists for).","solutions":["Use the original figma CDN URL returned by renderNodes/imageFills — do not rewrite it.","If behind a proxy that rewrites hosts, configure the proxy to preserve the figma host or bypass it for figma domains.","For local assets, use freezeLocalFile instead of freezeUrl.","Confirm the URL starts with https:// and the host is figma.com / a *.figma.com subdomain / *.amazonaws.com."],"exampleFix":"// before — proxy rewrote the host, SSRF guard rejects\nawait freezeUrl('https://cdn.corp-proxy.internal/asset.png', dest);\n\n// after — pass the original figma CDN url through unchanged\nawait freezeUrl('https://s3.us-east-1.amazonaws.com/figma/...', dest);","handlingStrategy":"validation","validationCode":"import { isAllowedFreezeUrl } from '.../figma/freeze';\nexport function assertFreezable(url: string): void {\n  if (!isAllowedFreezeUrl(url)) {\n    throw new Error(`${url} is not a figma CDN URL — refusing to fetch`);\n  }\n}\nassertFreezable(url);\nawait freezeUrl(url, dest);","typeGuard":null,"tryCatchPattern":"try {\n  await freezeUrl(url, dest);\n} catch (err) {\n  if (err instanceof Error && /refusing non-figma url/.test(err.message)) {\n    // log a security warning, do NOT bypass\n  } else throw err;\n}","preventionTips":["Never rewrite figma CDN URLs through a non-figma proxy before freezing.","For local assets use freezeLocalFile, not freezeUrl with a file:// or localhost URL.","Treat this error as a security signal — investigate how the non-figma URL entered the manifest."],"tags":["figma","freeze","security","ssrf","assets"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}