Strip EXIF metadata from uploaded images #23

Open
opened 2026-05-13 21:38:25 +02:00 by arne · 0 comments
Owner

Why

Photos from phones (iOS Photos, Android camera) routinely carry EXIF
metadata: GPS coordinates, camera serial, capture timestamp. The current
`POST /api/v1/uploads` pipeline (#22) writes bytes verbatim — meaning
sending an image leaks the user's location to every recipient.

This is a day-one privacy regression for the image-send flow as soon as
clients start using it.

Scope

Add an EXIF-stripping pass to `internal/api/upload.go` after the
imagesniff cross-check and before `uploads.Write`. JPEG and PNG both
have well-known metadata segments:

  • JPEG: strip all APPn (APP1/EXIF, APP2/ICC, etc.) and COM segments. Keep
    SOI, SOFn, DQT, DHT, DAC, DRI, SOS, image data, EOI.
  • PNG: strip all ancillary chunks except those critical for rendering
    (IHDR, IDAT, IEND, PLTE, tRNS, gAMA, sRGB, cHRM, iCCP for color
    correctness). Strip tEXt, zTXt, iTXt, eXIf, tIME, pHYs as a baseline.

A small dependency-free Go implementation is preferable (the bytes are
already in memory at that point — no need to round-trip through
`image.Decode` which would also re-encode).

Out of scope

  • Lossy re-encoding (covered separately by the image pipeline issue).
  • Anything beyond the two formats already accepted by imagesniff.

Acceptance

  • A JPEG uploaded with EXIF GPS tags is stored without those tags.
  • A PNG uploaded with tEXt comments is stored without them.
  • Round-trip rendering (download → display) is visually identical for
    the bitmap data.
  • Test fixtures cover both formats with known metadata segments.

Related: #22 (the upload endpoint that introduced this gap).

### Why Photos from phones (iOS Photos, Android camera) routinely carry EXIF metadata: GPS coordinates, camera serial, capture timestamp. The current \`POST /api/v1/uploads\` pipeline (#22) writes bytes verbatim — meaning **sending an image leaks the user's location** to every recipient. This is a day-one privacy regression for the image-send flow as soon as clients start using it. ### Scope Add an EXIF-stripping pass to \`internal/api/upload.go\` after the imagesniff cross-check and before \`uploads.Write\`. JPEG and PNG both have well-known metadata segments: - JPEG: strip all APPn (APP1/EXIF, APP2/ICC, etc.) and COM segments. Keep SOI, SOFn, DQT, DHT, DAC, DRI, SOS, image data, EOI. - PNG: strip all ancillary chunks except those critical for rendering (IHDR, IDAT, IEND, PLTE, tRNS, gAMA, sRGB, cHRM, iCCP for color correctness). Strip tEXt, zTXt, iTXt, eXIf, tIME, pHYs as a baseline. A small dependency-free Go implementation is preferable (the bytes are already in memory at that point — no need to round-trip through \`image.Decode\` which would also re-encode). ### Out of scope - Lossy re-encoding (covered separately by the image pipeline issue). - Anything beyond the two formats already accepted by imagesniff. ### Acceptance - A JPEG uploaded with EXIF GPS tags is stored without those tags. - A PNG uploaded with tEXt comments is stored without them. - Round-trip rendering (download → display) is visually identical for the bitmap data. - Test fixtures cover both formats with known metadata segments. Related: #22 (the upload endpoint that introduced this gap).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
posta/server#23
No description provided.