Skip to content

Validate attacker-controlled xref/ObjStm integers#3

Merged
pgundlach merged 1 commit into
mainfrom
claude/validate-xref-bounds
Jun 18, 2026
Merged

Validate attacker-controlled xref/ObjStm integers#3
pgundlach merged 1 commit into
mainfrom
claude/validate-xref-bounds

Conversation

@fank

@fank fank commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Problem

A crafted PDF can panic pdfdisassembler on untrusted input — three attacker-controlled integers reach a slice or make unvalidated:

  • xref stream /W with a negative width → the row decode slices row[a:b] with b < aslice bounds out of range, during Open.
  • ObjStm /First beyond the stream length → content[:first]slice bounds out of range.
  • ObjStm /N absurdly large → make([]pair, 0, n)makeslice: cap out of range / large allocation.

The ObjStm paths fire when the catalog or a name-tree object lives in an object stream (standard in PDF 1.5+). Found while hardening for a downstream consumer that parses untrusted invoice PDFs.

Fix

Validate before use, returning an error instead of panicking:

  • /W entries must be >= 0.
  • /First and /N are bounded by the decoded stream length — no object stream holds more entries (or a longer header) than it has bytes.

Tests

Minimal synthetic xref-stream / ObjStm PDFs:

  • TestXrefStreamNegativeWidthNoPanic, TestObjStmFirstOutOfRangeNoPanic, TestObjStmHugeNNoPanic — assert no panic on hostile values.
  • TestObjStmCatalogBaseline — a valid ObjStm catalog still resolves (guards against false positives).

Hostile values trip Go's slice/make size checks (recoverable panics), not real allocations — no large allocations in the test run. Full suite + go vet pass; gofmt-clean.

@fank fank force-pushed the claude/validate-xref-bounds branch 2 times, most recently from b22cb63 to 607bb81 Compare June 18, 2026 16:41
A crafted PDF could panic the parser during Open or object resolution:
- xref stream /W with a negative width -> row[a:b] with b < a (slice panic)
- ObjStm /First beyond the stream -> content[:first] (slice panic)
- ObjStm /N absurdly large -> make([]pair, 0, n) (makeslice panic / OOM)

Reject each with an error instead: /W entries must be >= 0, and /First and
/N are bounded by the decoded stream length (no ObjStm holds more entries
than it has bytes).

Tests build minimal xref-stream / ObjStm PDFs (including a valid control)
and assert no panic on hostile values.
@fank fank force-pushed the claude/validate-xref-bounds branch from 607bb81 to d8d025f Compare June 18, 2026 16:43
@fank fank marked this pull request as ready for review June 18, 2026 16:44
@fank fank requested a review from pgundlach June 18, 2026 16:44
@pgundlach

Copy link
Copy Markdown
Member

Very useful!

@pgundlach pgundlach merged commit 0e7b834 into main Jun 18, 2026
1 check passed
@pgundlach

Copy link
Copy Markdown
Member

I hope you don't mind that I've shortened the first line, some user agents cut the first line at 50 something chars. If I should not do this, please tell me

@fank

fank commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

nah its fine

@fank fank deleted the claude/validate-xref-bounds branch June 18, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants