Lab: PDF Metadata#
Current status: Verified · Detect: Yes · Remove: Yes · Last tested: 2026-08-13
← Back to the Lab · ← Back to the MarkMyAss cleaner
What this signal is#
PDF files carry two independent metadata containers:
- DocInfo (the
/Infodictionary): Title, Author, Producer, Creator, creation/modification timestamps, and other legacy fields. - XMP (
/Metadatastream): a structured XML metadata packet, which can duplicate or extend DocInfo and is what most modern tools (including many AI/PDF-export pipelines) actually write to.
Either can carry provenance information -- the tool that generated the PDF, an author name, timestamps -- independent of anything about the PDF's visible content.
What MarkMyAss can test#
Detection reads both containers directly from the PDF object graph via
pikepdf (a Python binding to
qpdf). Implementation:
src/ghostmark/detectors/metadata.py.
What MarkMyAss can remove#
Both the /Info dictionary and the /Metadata (XMP) stream are deleted
entirely from the PDF's object graph -- not blanked, removed. Pages,
fonts, images, text, links, and page order are untouched; MarkMyAss edits
the PDF's object graph directly rather than rasterizing or re-rendering
it. Implementation:
src/ghostmark/cleaners/pdf.py.
After cleaning, MarkMyAss reopens the produced PDF and confirms it's still structurally valid (parses, page count matches) before handing it back -- a metadata-removal bug that corrupts the file is treated as a cleaning failure, not a success.
What MarkMyAss cannot test#
- Metadata embedded in individual PDF objects in nonstandard, non-DocInfo/non-XMP locations (rare, but possible in hand-crafted or unusual PDFs). MarkMyAss's detector targets the two standard containers.
- Any provenance signal embedded in images placed inside the PDF (those are covered separately by MarkMyAss's image EXIF/XMP/IPTC detectors when you clean the image directly, not automatically unpacked from inside a PDF).
Verification methodology#
Independent verification uses ExifTool
(exiftool -j -G1 -a -s FILE), a long-established, widely trusted
third-party tool MarkMyAss does not control. Every property ExifTool
reports is categorized into embedded_metadata / structural /
filesystem / computed so that, for example, PDF:PageCount (a
structural fact needed for the file to make sense) is never confused
with PDF:Author (metadata MarkMyAss actually targets). See
src/ghostmark/independent_verify.py
for the exact categorization rules.
A result only counts as independently verified clean when ExifTool finds
zero embedded_metadata-category tags in the cleaned output.
Reproducible test commands#
ghostmark inspect src/ghostmark/corpus/pdf/docinfo-xmp.pdf --json
ghostmark clean src/ghostmark/corpus/pdf/docinfo-xmp.pdf
ghostmark verify src/ghostmark/corpus/pdf/docinfo-xmp.ghostmark.pdf --receipt receipt.json
# Independently, with ExifTool directly:
exiftool -j -G1 -a -s src/ghostmark/corpus/pdf/docinfo-xmp.pdf
exiftool -j -G1 -a -s src/ghostmark/corpus/pdf/docinfo-xmp.ghostmark.pdf
Covered by the automated regression suite:
tests/test_pdf.py,
tests/test_corpus.py,
and the real-ExifTool integration suite
tests/integration/test_exiftool_real.py.
Related pages#
- AI Metadata Cleaner -- the practical, format-by-format version of this page, covering PDF, JPEG, PNG, and WebP.
Sources#
- PDF 2.0 specification (ISO 32000-2) --
/Infodictionary and/Metadatastream - XMP Specification, Adobe/ISO 16684
- pikepdf documentation
- ExifTool
Something outdated or inaccurate?#
Open an issue or submit a
pull request against
src/ghostmark/web/content/lab/pdf-metadata.md.
Last reviewed: 2026-08-13