PDF Xref Table and Trailer Explained (ISO 32000)

This article is a snapshot – content was accurate as of May 2026. The product evolves actively; specific counts, examples, and detection rules may have changed since publication – see the changelog for the current state.
A PDF is not read from top to bottom like a web page. A reader opens it at the end, finds an index, and jumps straight to the parts it needs. That index is the cross-reference table, usually shortened to xref. One consequence of that design is that a PDF can still contain earlier versions of itself.
This article explains what the xref table is, how editors extend it, and what that means for anyone who has to decide whether to trust a document. Everything about the file format below is public specification material. For how HTPBE? combines structure with other evidence, see how the analysis works.
What the PDF cross-reference table is
A PDF file is a collection of numbered objects – pages, fonts, images, the document information dictionary, annotations – written at arbitrary byte positions. The cross-reference table maps each object number to its byte offset, so a reader can open the file and fetch any object without scanning everything before it.
The specification defines the table in section 7.5.4 of ISO 32000-1, and the same standard is mirrored by Adobe as PDF 32000-1:2008. A minimal xref section looks like this:
xref
0 6
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000266 00000 n
0000000397 00000 nEach entry is exactly 20 bytes, including the line ending. It holds a byte offset (0000000058), a generation number (00000), and a keyword: n for an object in use, f for a free entry.
Entries are grouped into subsections, each introduced by a line giving the first object number and the number of entries. A subsection covers a contiguous range of object numbers, and the table as a whole has to account for every number from 0 up to the highest one in the file.
Free entries and generation numbers
Object 0 is always free, with generation 65535, and heads a linked list of free entries. In a free entry the first field is not an offset but the number of the next free object. When an object is deleted, its entry becomes free and its generation number goes up by one, so the next object created under that number is a distinct object. A number whose generation reaches 65535 is never reused. This is why f entries can carry non-zero numbers.
After the table comes the trailer, described in section 7.5.5:
trailer
<<
/Size 6
/Root 1 0 R
/Info 2 0 R
>>
startxref
431
%%EOFstartxref gives the byte offset where the xref begins. Because a reader works backward from the end of the file, startxref is the first thing it looks for. /Root points to the document catalogue and /Info to the document information dictionary, the place where fields such as Producer and CreationDate live. The complete reference to PDF metadata fields covers those.
Cross-reference streams and hybrid files
From PDF 1.5, the index can be stored as a cross-reference stream (section 7.5.8) instead of a text table. The stream is an ordinary object with /Type /XRef, and its dictionary doubles as the trailer: it carries /Size, /Root, /Info and, for later sections, /Prev.
The binary body is described by two entries. /W gives the byte width of each field in an entry, and /Index lists the subsections the stream covers. Each entry begins with a type:
| Type | Meaning | Remaining fields |
|---|---|---|
| 0 | Free object | Next free object number, generation |
| 1 | Object in use | Byte offset, generation |
| 2 | Compressed object | Number of the object stream that holds it, index within that stream |
Type 2 is what lets PDF 1.5 files keep many small objects inside compressed object streams (section 7.5.7) while still being able to find each one. A plain-text table cannot express that, which is the main reason the stream form exists.
Some files mix both forms. A hybrid-reference file (section 7.5.8.4) keeps a conventional table for older readers and points to a cross-reference stream from the trailer of an update section with /XRefStm; a reader looks there before it follows /Prev.
Incremental updates: how a PDF is extended
The standard describes a second way to save a file, called an incremental update (section 7.5.6). Instead of rewriting the whole file, the writer appends the changes to the end and leaves the original bytes untouched. The specification says changes ‘shall be appended to the end of the file, leaving its original contents intact’.
An incremental save therefore does four things:
- New or changed objects are written after the existing
%%EOF - A new cross-reference section is written, listing only the objects that changed
- A new trailer is written, with a
/Preventry pointing to the previous xref section - A new
%%EOFcloses the update
The result looks like this:
[original body — objects 1–5]
%%EOF
[new object 2 — replaced Info dictionary]
[new object 5 — page object, now listing an annotation]
[new object 6 — the annotation]
xref
0 1
0000000000 65535 f
2 1
0000000640 00000 n
5 2
0000000780 00000 n
0000000905 00000 n
trailer
<<
/Size 7
/Root 1 0 R
/Info 2 0 R
/Prev 431 ← points to the earlier xref
>>
startxref
1010
%%EOFThe example is simplified. A real update lists every object it touches, and offsets depend on the file.
A reader starts from the last startxref, reads the newest section, follows /Prev back, and builds the full table. When the same object number appears more than once, the newest copy wins. That is how an edit takes effect without the older bytes being removed.
The practical consequence is that a file can contain its own earlier versions, and the order in which changes were made is kept in the structure. Appending also makes it quick to save a small change to a large document, which is the reason the mechanism exists.
More than one section is normal – and it is not a verdict
Incremental saving exists for good reasons, so a file with several sections is not suspicious in itself. The specification itself notes that a table starts as one section, or two in a linearized file (Annex F, the layout used for fast web viewing), so even a file that has never been edited can contain more than one. Legitimate workflows that append to a PDF include:
- Digital signatures. Signing adds a revision, and each further signer adds another.
- Form filling. Completing and saving a fillable form usually appends the entered values.
- Annotations and comments. Review markup is stored as new objects.
- Document management systems. Stamps, page numbers and archival metadata are often added after export.
So the right reading of an appended section is narrow. It can show that the file was written more than once. Whether those later writes were routine, such as a signature, or changed what the document says depends on what changed and who changed it. The same applies in reverse: a file with no appended updates has not been proven authentic. Digital signatures and metadata answer different questions, and neither one settles authenticity alone.
What this means when you check a document
If you review documents for a living – loan files, payslips, claims, contracts – three points are worth keeping:
- A file’s own structure can show that it was changed after it was created. That evidence lives in the file, not in what the page displays, so a document that looks right on screen can still carry it.
- Structure is one signal among several. It is read together with other evidence in the file, not as a standalone test. Anatomy of a modified PDF gives the overview, and binary PDF modification detection covers the approach and its limits.
- Different tools leave different marks. The guide to common PDF editors and the traces they leave looks at the editor side.
Reading the structure yourself is possible but slow, and interpretation takes practice. How to view a PDF’s edit history is the next step if you want to read the timeline of a file. The free PDF metadata viewer shows the metadata fields stored in a file; it does not give a verdict on modification.
What a result means
HTPBE? reports one of three outcomes for a document:
- Modified – the check found evidence that the file was changed after it was created.
- Intact – no such evidence was found. This is not a guarantee that the content is true or that the document is genuine.
- Inconclusive – this kind of file cannot support a reliable answer either way. What inconclusive means explains the outcome in detail.
HTPBE? detects modification after creation. It does not judge whether the content of a document is truthful, and a document produced from scratch is outside what any check of file structure can establish. PDF forensics without the original file covers what remains possible when there is no reference copy to compare against.
Checking documents at scale
The forensic PDF API page lists what the file-level analysis covers and shows what a full result looks like.
If you receive PDFs through an intake process, the HTPBE? API lets you submit a document and get a result back programmatically, with free test keys for trying it on synthetic documents first. The entry plan covers 30 checks a month – see current pricing. A result is best used as a prompt for human review, not as the last word on a document.
For the reasoning behind reading the file instead of the rendered page, with a worked example of two statements that look identical, see why PDF modification checks read the file, not the page.