High-trust EXIF removal with a transparent supply chain.
Two-stage pipeline: byte-level APP wipe via jpegtran,
then allowlisted EXIF rebuild via ExifTool.
Closes the gap parser-based tools leave open.
Parser-based tools can only see segments they know about. jpegtran operates at the byte level — it removes
everything regardless of format, including segments from obscure camera manufacturers.
The allowlist rebuild ensures the resulting image is still technically complete and
usable, without carrying anything identifying.
--from-input watches a hot directory. Works with PhotoSync, rclone, FTP uploads.--rename replaces capture-timestamp filenames with random hex, UUID, or custom format strings.--dry-run and --show-tags let you inspect before committing to any changes.--copyright.--read-only, --no-new-privileges, and --tmpfs.Every JPEG uploaded from a camera runs through scrubexif before landing in PhotoPrism. GPS coordinates, camera serial numbers, and maker notes are stripped at intake. Only technical shooting data — exposure, ISO, focal length — is kept. The gallery is public; the metadata is not.
# Scrub all JPEGs in $PWD → writes to $PWD/output/
docker run --rm \
-v "$PWD:/photos" \
per2jensen/scrubexif:0.7.22
Originals are untouched in $PWD/. Scrubbed copies go to $PWD/output/.
Run is refused if output/ already exists — no accidental overwrites.
# Hardened in-place (destructive) scrub
docker run -it --rm \
--read-only --security-opt no-new-privileges \
--tmpfs /tmp \
-v "$PWD:/photos" \
per2jensen/scrubexif:0.7.22 --clean-inline
Overwrites originals in-place. Use when you want the file count to stay the same and you don't need a non-destructive copy. Container runs fully read-only.
# Fully anonymous — 8-char random hex filenames docker run -it --rm \ --read-only --security-opt no-new-privileges \ --tmpfs /tmp \ -v "$PWD:/photos" \ per2jensen/scrubexif:0.7.22 --clean-inline --rename "%r8" --recursive # Keep camera prefix, drop timestamp per2jensen/scrubexif:0.7.22 --clean-inline --rename "D80_%r6"
Filenames leak too. 2026-04-07_11-13-45.jpeg reveals exact capture time.
D80_ identifies the camera body.
Tokens: %r (random hex) · %u (UUID) · %n (counter) · %Y (year) · %m (month)
# Create directories, then run auto-intake mode
mkdir input scrubbed processed errors
docker run -it --rm \
--read-only --security-opt no-new-privileges \
--tmpfs /tmp \
-v "$PWD/input:/photos/input" \
-v "$PWD/scrubbed:/photos/output" \
-v "$PWD/processed:/photos/processed" \
-v "$PWD/errors:/photos/errors" \
per2jensen/scrubexif:0.7.22 --from-input
input/ → new uploads · output/ → scrubbed · processed/ → originals · errors/ → duplicates (with --on-duplicate move).
Pair with --stable-seconds for hot upload directories.
| Flag | Description |
|---|---|
| --from-input | Auto intake mode — watches input/ directory |
| --clean-inline | In-place scrub (destructive — modifies originals) |
| --rename FORMAT | Rename output files using a format string (spec ↗) |
| --paranoia | Byte-level wipe only — zero metadata survives (no EXIF, no ICC) |
| --preview | No writes — view what would be changed |
| --dry-run | Simulate the run without writing any files |
| --show-tags | Inspect metadata before/after |
| -o, --output DIR | Write scrubbed files to DIR (default safe mode) |
| --stable-seconds N | Intake stability window (hot upload directories) |
| --on-duplicate | delete | move — what to do with duplicate filenames |
| --delete-original | Remove originals after successful scrub in auto mode |
| --copyright | Stamp copyright string into EXIF/XMP |
| --comment | Stamp comment into EXIF/XMP |
| --recursive | Process subdirectories |
| -q, --quiet | No output on success |
Full CLI reference → DETAILS.md ↗
Every release image is cryptographically signed using cosign keyless signing via the Sigstore public infrastructure. The signature is tied to the exact GitHub Actions run — no long-lived signing keys exist anywhere.
VERIFY ANY RELEASE — requires cosign
cosign verify per2jensen/scrubexif:0.7.22 \ --certificate-identity-regexp="https://github.com/per2jensen/scrubexif" \ --certificate-oidc-issuer="https://token.actions.githubusercontent.com"
ExifTool by Phil Harvey — metadata extraction and selective tag write-back (GPL-1.0-or-later / Artistic) · jpegtran from libjpeg-turbo — lossless byte-level JPEG transformation · cosign — image signing · Syft — SBOM generation · Grype — vulnerability scanning · Ubuntu 24.04 — base image