{"record":{"id":"8602d6b6d96f71f1","repo":"paperclipai/paperclip","slug":"heif-metadata-nesting-is-too-deep","errorCode":null,"errorMessage":"HEIF metadata nesting is too deep","messagePattern":"HEIF metadata nesting is too deep","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/media.ts","lineNumber":22,"sourceCode":"import { MAX_ATTACHMENT_BYTES } from \"../../attachment-types.js\";\n\nconst require = createRequire(import.meta.url);\nconst 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\") {","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/media.ts#L4-L40","documentation":"validateHeifDimensions parses the ISO-BMFF box tree of a HEIF/HEIC buffer with a bounded recursive visit() before any native decoder runs. If recursion depth exceeds 8 (meta/iprp/ipco containers nested too deeply) it throws \"HEIF metadata nesting is too deep\". This is a hardening limit against maliciously crafted deeply nested files that could exhaust the parser or decoder.","triggerScenarios":"Calling validateHeifDimensions (directly or via validatePhotonImage/photonHeifPreview) on a HEIF buffer whose meta/iprp/ipco box nesting is deeper than 8 levels — interactions.ts-independent, media.ts:22.","commonSituations":"Uploading a crafted/fuzzed HEIC file; unusual but legitimate deeply nested HEIF metadata from exotic camera tooling; a file mislabeled as image/heic that happens to nest boxes deeply.","solutions":["Reject the upload — this limit is intentional; re-encode the image with standard tooling (e.g. sips, ImageMagick, libheif) to flatten metadata.","Strip metadata from the HEIF before re-submitting (exiftool -all= or heif-convert/re-encode).","Verify the file opens in a standard viewer; if not, the file is likely corrupt or malicious — do not process.","If legitimate depth is truly required, raise the depth limit in media.ts with a code change and fresh security review."],"exampleFix":"// shell re-encode before upload\n// before: file.heic with 10-level nested meta boxes\n// after: magick file.heic -strip flattened.heic","handlingStrategy":"validation","validationCode":"// heuristic pre-check: reject implausibly large HEIF metadata before server-side validation\nfunction plausibleHeifSize(buf: Buffer): boolean {\n  return buf.length > 0 && buf.length <= MAX_ATTACHMENT_BYTES && buf.toString(\"ascii\", 4, 8) === \"ftyp\";\n}","typeGuard":"function looksLikeHeif(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 === \"HEIF metadata nesting is too deep\") {\n    return rejectUpload(\"HEIF file has unsafe metadata nesting; re-encode the image\");\n  }\n  throw e;\n}","preventionTips":["Re-encode HEIC/HEIF from untrusted sources with mainstream tooling before upload.","Strip extraneous metadata (exiftool -all=) from images originating outside standard cameras.","Never attempt to bypass depth limits on user-supplied files — treat deep nesting as hostile.","Keep uploads within MAX_ATTACHMENT_BYTES to fail fast on other guards."],"tags":["heif","isobmff","security","input-validation"],"backgroundTag":"value-out-of-range","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"}