{"record":{"id":"f4dee4cbd2d5305f","repo":"paperclipai/paperclip","slug":"invalid-heif-box-structure","errorCode":null,"errorMessage":"Invalid HEIF box structure","messagePattern":"Invalid HEIF box structure","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/media.ts","lineNumber":25,"sourceCode":"const MAX_PIXELS = 50_000_000;\nexport const HEIF_CONTENT_TYPES = new Set([\n  \"image/heic\",\n  \"image/heif\",\n  \"image/heic-sequence\",\n  \"image/heif-sequence\",\n]);\n\n/** Validate bounded ISO-BMFF structure before invoking any native decoder. */\nexport function validateHeifDimensions(body: Buffer): void {\n  let boxes = 0;\n  let dimensions = 0;\n  let totalPixels = 0;\n  let branded = false;\n  const visit = (start: number, end: number, depth: number) => {\n    if (depth > 8) throw new Error(\"HEIF metadata nesting is too deep\");\n    for (let at = start; at < end; ) {\n      if (++boxes > 4096 || end - at < 8)\n        throw new Error(\"Invalid HEIF box structure\");\n      let size = body.readUInt32BE(at);\n      const type = body.toString(\"ascii\", at + 4, at + 8);\n      let header = 8;\n      if (size === 1) {\n        if (end - at < 16) throw new Error(\"Invalid HEIF box length\");\n        const extended = body.readBigUInt64BE(at + 8);\n        if (extended > BigInt(body.length))\n          throw new Error(\"HEIF box exceeds file bounds\");\n        size = Number(extended);\n        header = 16;\n      } else if (size === 0) size = end - at;\n      if (size < header || at + size > end)\n        throw new Error(\"HEIF box exceeds file bounds\");\n      const content = at + header;\n      if (type === \"ftyp\") {\n        if (size < header + 8) throw new Error(\"HEIF file type is missing\");\n        const brands = body.toString(\"ascii\", content, at + size);\n        branded = /heic|heix|hevc|hevx|mif1|msf1/.test(brands);","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/media.ts#L7-L43","documentation":"The same bounded ISO-BMFF walker throws \"Invalid HEIF box structure\" when the per-container box count exceeds 4096 or fewer than 8 bytes remain where a box header is required. It is a structural sanity check ensuring the buffer parses as well-formed ISO-BMFF boxes before native decoding.","triggerScenarios":"A HEIF buffer containing more than 4096 sibling boxes in one container, or a truncated buffer where the remaining range (end - at) is < 8 bytes mid-iteration (media.ts:24-25).","commonSituations":"Corrupted or truncated HEIC upload (incomplete download/transfer); fuzzed or malicious file with thousands of tiny boxes; non-HEIF bytes declared with an image/heic content type.","solutions":["Re-download/re-export the image — the file is corrupt or truncated; verify with `heif-info` or `ffprobe`.","Confirm the declared content type matches the actual bytes (magic bytes should be ftyp).","Re-encode the source image to HEIC with standard tooling before uploading.","If malicious input is suspected, keep it blocked; this guard is intentional."],"exampleFix":"// verify before upload\n// before: truncated file.heic (cut off mid-transfer)\n// after: ffprobe file.heic && re-export, or compare byte size against source","handlingStrategy":"validation","validationCode":"function heifStructureLooksSane(buf: Buffer): boolean {\n  if (buf.length < 12 || buf.toString(\"ascii\", 4, 8) !== \"ftyp\") return false;\n  let at = 0, boxes = 0;\n  while (at + 8 <= buf.length && boxes++ < 4096) {\n    const size = buf.readUInt32BE(at);\n    if (size < 8 && size !== 0) return false;\n    at += size === 0 ? buf.length - at : size;\n  }\n  return at <= buf.length;\n}","typeGuard":"function hasFtypHeader(b: Buffer): b is Buffer {\n  return b.length >= 12 && b.toString(\"ascii\", 4, 8) === \"ftyp\";\n}","tryCatchPattern":"try {\n  validateHeifDimensions(body);\n} catch (e) {\n  if (e instanceof Error && e.message === \"Invalid HEIF box structure\") {\n    return rejectUpload(\"File is truncated or not valid HEIF; please re-export it\");\n  }\n  throw e;\n}","preventionTips":["Verify uploads complete (checksum/byte count) before validation.","Run a local ffprobe/heif-info sanity check in tooling before submitting files.","Reject content types that don't match magic bytes early in the upload path.","Treat thousands of tiny boxes as malicious; never relax the 4096 cap for untrusted input."],"tags":["heif","isobmff","corrupt-file","input-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}