{"record":{"id":"578e93122563d90c","repo":"siyuan-note/siyuan","slug":"avif-invalid-exif-ifd-offset","errorCode":null,"errorMessage":"avif: invalid exif ifd offset","messagePattern":"avif: invalid exif ifd offset","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/heif/internal/h265heic/exif.go","lineNumber":291,"sourceCode":"\t\treturn errors.New(\"avif: exif data too short\")\n\t}\n\n\tr := &exifReader{data: data}\n\tswitch {\n\tcase data[0] == 'I' && data[1] == 'I':\n\t\tr.littleEndian = true\n\tcase data[0] == 'M' && data[1] == 'M':\n\tdefault:\n\t\treturn errors.New(\"avif: invalid exif byte order marker\")\n\t}\n\n\tif r.uint16(2) != 42 {\n\t\treturn errors.New(\"avif: invalid exif magic number\")\n\t}\n\n\tifdOffset := r.uint32(4)\n\tif ifdOffset < 8 || int(ifdOffset) >= len(data) {\n\t\treturn errors.New(\"avif: invalid exif ifd offset\")\n\t}\n\n\texifIFDOffset, gpsIFDOffset := parseIFD(r, int(ifdOffset), exif)\n\tif exifIFDOffset > 0 {\n\t\tparseExifSubIFD(r, exifIFDOffset, exif)\n\t}\n\tif gpsIFDOffset > 0 {\n\t\tparseGPSSubIFD(r, gpsIFDOffset, exif)\n\t}\n\n\treturn nil\n}\n\n// eachEntry walks the entries of an IFD, resolving each value to its offset.\nfunc eachEntry(r *exifReader, offset int, fn func(tag, dataType uint16, count uint32, valueOffset int)) {\n\tif offset < 0 || offset+1 >= len(r.data) {\n\t\treturn\n\t}","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/heif/internal/h265heic/exif.go#L273-L309","documentation":"The EXIF header's IFD offset field (at TIFF offset 4) must be at least 8 (past the header itself) and within the payload bounds. parseExifData read an offset pointing before the header or beyond the data, so the IFD (directory of tags) cannot be located. This indicates a corrupt or maliciously crafted EXIF block.","triggerScenarios":"DecodeExif on a payload where the uint32 at offset 4 is < 8 or >= len(data) — truncated EXIF payloads where the header claims offsets into data that was cut off, or crafted values.","commonSituations":"Truncated sync/download cutting the EXIF payload after the header; writers emitting offsets relative to the wrong base (common off-by-8 confusion between file-relative and item-relative offsets).","solutions":["Check whether the writer used file-relative IFD offsets that need rebasing to the payload start","Validate the payload is complete (compare item extent length against declared offsets) before parsing","Treat EXIF as unreadable and render the image with default orientation","Sanitize/strip EXIF and re-export the file if the source is untrusted"],"exampleFix":"// before\nifdOffset := r.uint32(4)\n// after\nifdOffset := r.uint32(4)\n// writers sometimes emit offsets relative to the TIFF header start; rebase\nif ifdOffset < 8 && ifdOffset+8 < uint32(len(data)) {\n\tifdOffset += 8\n}","handlingStrategy":"validation","validationCode":"func hasBoundedIFD(data []byte) bool {\n\tif len(data) < 8 {\n\t\treturn false\n\t}\n\tr := newExifReader(data)\n\toff := r.uint32(4)\n\treturn off >= 8 && int(off) < len(data)\n}","typeGuard":"func safeIFDOffset(data []byte) (int, bool) {\n\tif len(data) < 8 {\n\t\treturn 0, false\n\t}\n\toff := int(binary.BigEndian.Uint32(data[4:8]))\n\tif off < 8 || off >= len(data) {\n\t\treturn 0, false\n\t}\n\treturn off, true\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"invalid exif ifd offset\") {\n\tlog.Warnf(\"EXIF IFD offset out of bounds; skipping metadata: %v\", err)\n\treturn nil\n}","preventionTips":["Bound-check every offset read from untrusted metadata before use","Watch for writers using file-relative vs item-relative offset bases and rebase consistently","Verify payload completeness (declared extents vs actual length) after sync/download","Treat EXIF as optional metadata; never fail the image pipeline on its corruption"],"tags":["exif","metadata","ifd","corrupt-data"],"backgroundTag":"value-out-of-range","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}