Strip EXIF/GPS metadata from images by default (currently only when compression is on) #109

Closed
opened 2026-09-17 13:27:07 -04:00 by jared · 1 comment
Owner

Verified 2026-09-17: metadata is only dropped as a side effect of the opt-in compression path (src/app/utils/imageCompression.ts re-encodes through a canvas, which bakes orientation and discards EXIF). With compression off — the default — the original file is uploaded byte-for-byte, so a phone photo carries its GPS coordinates, device model and timestamp to everyone in the room (and to the homeserver's media store).

Scope

  • Metadata-only strip for JPEG/PNG/WebP/HEIC-as-supported on every image upload path (composer attach, paste, drag-drop, avatar/room avatar, GIF upload excluded): remove EXIF/XMP/IPTC segments without re-encoding pixels, so quality is untouched and the file stays the same format. Apply the EXIF orientation first if the strip would otherwise change how the image displays (rotate via canvas only in that case, or keep the orientation tag alone).
  • Setting under Settings → Privacy: "Remove photo metadata (location, camera) before sending" — default on.
  • Show "metadata removed" in the upload card so users know.
  • Unit tests on fixture files with a GPS EXIF block.

Notes

  • Videos are out of scope for v1 (container metadata needs a demuxer); note it in the tile description.
Verified 2026-09-17: metadata is only dropped as a side effect of the **opt-in** compression path (`src/app/utils/imageCompression.ts` re-encodes through a canvas, which bakes orientation and discards EXIF). With compression off — the default — the original file is uploaded byte-for-byte, so a phone photo carries its GPS coordinates, device model and timestamp to everyone in the room (and to the homeserver's media store). ### Scope - Metadata-only strip for JPEG/PNG/WebP/HEIC-as-supported on every image upload path (composer attach, paste, drag-drop, avatar/room avatar, GIF upload excluded): remove EXIF/XMP/IPTC segments without re-encoding pixels, so quality is untouched and the file stays the same format. Apply the EXIF orientation first if the strip would otherwise change how the image displays (rotate via canvas only in that case, or keep the orientation tag alone). - Setting under Settings → Privacy: "Remove photo metadata (location, camera) before sending" — **default on**. - Show "metadata removed" in the upload card so users know. - Unit tests on fixture files with a GPS EXIF block. ### Notes - Videos are out of scope for v1 (container metadata needs a demuxer); note it in the tile description.
jared added this to the Features 2026-Q4 milestone 2026-09-17 13:27:07 -04:00
jared added the enhancementpriority: highsecurityarea: media labels 2026-09-17 13:27:07 -04:00
jared self-assigned this 2026-09-17 13:27:07 -04:00
Author
Owner

Done in be2c2025.

How: utils/stripImageMetadata.ts edits the container, never the pixels — JPEG drops APP1 (EXIF/XMP), APP13 (IPTC) and COM segments; PNG drops eXIf plus tEXt/iTXt/zTXt/tIME (XMP lives in iTXt); WebP drops EXIF/XMP chunks, clears the VP8X flag bits and rewrites the RIFF size. JFIF/ICC/colour chunks stay, so quality and colour management are untouched. Orientation: when a JPEG's EXIF Orientation ≠ 1 a minimal EXIF block holding only that tag is written back, so sideways-stored phone photos still display upright without re-encoding. HEIC/video/GIF pass through (noted in the setting text).

Where: before encryption in filesToUploadItems (attach, paste, drag-drop, share target) and on user/room avatar picks. GIF upload excluded. Setting → General → Privacy "Remove Photo Metadata Before Sending", default on. Upload card shows "Photo metadata removed (location, camera, time)".

Tests: generated fixtures with a GPS IFD (JPEG orientation 6, JPEG + comment, PNG with eXIf + XMP, WebP with EXIF) — 7 unit tests: model/GPS/timestamp gone, SOS→EOI bytes identical, orientation read back = 6, RIFF size correct. End to end: uploaded gps.jpg through the composer, downloaded what Synapse stored → decodes, exif = {Orientation: 6}, GPS IFD empty, 841 → 669 bytes.

upload card

Done in be2c2025. **How:** `utils/stripImageMetadata.ts` edits the container, never the pixels — JPEG drops APP1 (EXIF/XMP), APP13 (IPTC) and COM segments; PNG drops `eXIf` plus `tEXt`/`iTXt`/`zTXt`/`tIME` (XMP lives in `iTXt`); WebP drops `EXIF`/`XMP ` chunks, clears the VP8X flag bits and rewrites the RIFF size. JFIF/ICC/colour chunks stay, so quality and colour management are untouched. **Orientation:** when a JPEG's EXIF Orientation ≠ 1 a minimal EXIF block holding only that tag is written back, so sideways-stored phone photos still display upright without re-encoding. HEIC/video/GIF pass through (noted in the setting text). **Where:** before encryption in `filesToUploadItems` (attach, paste, drag-drop, share target) and on user/room avatar picks. GIF upload excluded. Setting → General → Privacy "Remove Photo Metadata Before Sending", default **on**. Upload card shows "Photo metadata removed (location, camera, time)". **Tests:** generated fixtures with a GPS IFD (JPEG orientation 6, JPEG + comment, PNG with eXIf + XMP, WebP with EXIF) — 7 unit tests: model/GPS/timestamp gone, SOS→EOI bytes identical, orientation read back = 6, RIFF size correct. End to end: uploaded `gps.jpg` through the composer, downloaded what Synapse stored → decodes, `exif = {Orientation: 6}`, GPS IFD empty, 841 → 669 bytes. ![upload card](https://code.lotusguild.org/attachments/4c64bfd1-9fee-46ec-9c31-2d35e8c0ae6d)
jared closed this issue 2026-09-20 14:23:04 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#109