Skip to content

Bump VellumPdf.Layout from 1.5.4 to 2.3.0 - #55

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/nuget/dependencies/VellumPdf.Layout-2.3.0
Closed

Bump VellumPdf.Layout from 1.5.4 to 2.3.0#55
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/nuget/dependencies/VellumPdf.Layout-2.3.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Sep 2, 2026

Copy link
Copy Markdown

Updated VellumPdf.Layout from 1.5.4 to 2.3.0.

Release notes

Sourced from VellumPdf.Layout's releases.

2.3.0

Breaking changes

  • A same-revision /XRefStm no longer overrides a classic cross-reference table's free entry
    for the same object.
    Given one revision whose classic table marks object N free and whose
    /XRefStm defines it, PdfReader now resolves N to null, matching qpdf; it previously
    resolved N from the stream. The construct is describable beyond a hand-freed /Contents: an
    incremental update from a writer that copies /XRefStm forward without understanding it, and
    also carries the previous revision's free entries along unchanged, produces exactly this shape —
    the case MatthiasValvekens describes in
    pdf-association/pdf-issues#​237, by
    his own account without having checked it against a real processor ("I'm not aware of any
    processors that do either of this, so maybe my intuition is completely wrong"). The
    cross-section arrangement ISO 32000-2 §7.5.8.4 actually describes, where the free entry sits in
    an earlier /Prev revision, is unaffected only in the two-revision case; a hybrid revision
    sitting between two others in a /Prev chain is not exempt, and loses its own copy the same way
    a same-revision one does while also suppressing whatever a still-older revision defined. What
    survives a chain like that is the definition in whichever revision is newest among the ones that
    mention the object at all, not simply whichever one sits outside a same-revision pairing. This
    aligns with the reading in issue #​237, open at the time of writing; if it or errata
    #​523 resolves the other way, this is
    revisited. VellumPdf.Reader is still Preview, where a behaviour change would ordinarily stay
    under Changed, but silently dropping rendered content is closer to what this section otherwise
    covers than a changed exception type is, so it's recorded here instead. (#​206)

    Consequences, measured rather than assumed except where a bullet says otherwise — the /Encrypt
    shape has no test, and the /DecodeParms half rests on a code reading rather than a fixture:

    • A page's content stream can disappear: if N is a page's /Contents, the page now has no
      content stream where it had one.
    • A page can disappear outright, not just its content. If N is the page-tree root, the page
      count drops from 1 to 0; if N is an intermediate /Pages node, freeing it drops only its own
      subtree — a three-page document with a two-page branch under that node loses those two pages
      and keeps the third, 3 becoming 1. The surviving root still declares its old /Count, so a
      caller trusting /Count and one walking /Kids now disagree. PreflightContext.WalkPages
      walks /Kids the same way, so page-scoped PDF/A rules silently stop covering the lost subtree
      too.
    • A rarer variant costs more: if N is the object an /Encrypt reference points at, the document
      now fails to open with InvalidDataException instead of decrypting, because /Encrypt can no
      longer resolve to a dictionary at all. This shape has no test yet.
    • Worse still, if N is the catalog itself, the document does not open at all: PdfReader.Open
      throws InvalidDataException: Malformed PDF: /Root does not resolve to a dictionary. where it
      previously opened.
    • A /Filter or /DecodeParms object resolving to null does not degrade to null output —
      it produces wrong bytes. PdfFilters.GetFilterList treats an unresolvable /Filter as no
      filter at all, so GetDecodedStreamData returns the raw, still-encoded body. Measured: a
      24-byte plaintext body, FlateDecode-compressed to 32 bytes (zlib header 78 9C), comes back as
      those 32 raw bytes instead of the 24-byte plaintext once its /Filter reference is freed this
      way; a byte-identical control with the filter object live decodes correctly. /DecodeParms
      degrades the same way — a PNG predictor's rows are never undone. qpdf degrades identically
      here, so this is not a divergence from the oracle, only from what this entry previously implied
      the general case is.
      ... (truncated)

2.2.0

Breaking changes

  • PdfDictionary.Set, TryGet and Get now throw ArgumentNullException for a null key.
    Previously TryGet(null, out _) returned false, Get(null) returned null, and
    Set(null, value) appended an entry that only failed later — with a NullReferenceException out
    of WriteTo, once the dictionary was serialised. All three are Stable API, which is why this is
    recorded here rather than under Security, where the rest of this fix lives: without the guard, a
    null key would behave differently depending on which side of the internal indexing threshold a
    dictionary sits — returning false below it, throwing above it — exactly the property that
    threshold is supposed to be free to move without changing what callers observe. (#​208)

Security

  • OwnerPassword = "" beside a real UserPassword produced a file with no real password
    protection at all, in every release from v1.0.0 through v2.1.0.
    ?? treats an empty string as
    a value, not as "unset", so that combination sealed /O and /OE (ISO 32000-2 §7.6.4.4.6,
    Algorithm 9) under the empty password instead of falling back to the user password. At /R 6 an
    empty password fails the /U check and satisfies the /O check, so any conforming reader lands
    on owner access when no password is supplied. That is a property of the file itself, not of the
    order a particular reader tries /U and /O in. Verified concretely: a file written by v2.1.0
    with UserPassword = "hunter2", OwnerPassword = "" opens with no password supplied at all,
    and the catalog, hence the whole object graph, decrypts. The document's confidentiality is gone,
    not merely its permission flags: nothing enforced Permissions, but nothing enforced
    UserPassword either. OwnerPassword = "" beside a non-empty UserPassword now throws instead
    of producing a file. Both passwords empty is unchanged, since an unprotected document is
    legitimate and ISO 32000-2 permits an empty owner password. OwnerPassword = null is unchanged
    too: that is the documented fallback to the user password as owner, and it does not reproduce
    this defect (/O is sealed under the real user password, not the empty string) — though anyone
    who can open the document still holds owner access under it, so Permissions still binds nobody.
    The guard sits in StandardSecurityHandler's constructor, which is Stable API and callable
    directly, and in PdfDocument.Encrypt, so the failure surfaces at the call site rather than at
    Save(); VellumPdf.Layout.Document.Encrypt inherits it by delegation. (EncryptionSetup.TryAuthenticate,
    this library's own authentication order, is why our reader reports such a file's access level as
    owner rather than user — that explains what we report, not why the exposure exists.)

    A document already written with this shape cannot be fixed in place: correcting it means
    re-deriving /O and /OE, which needs a real owner password behind them from the start. Affected
    documents must be re-encrypted from the original plaintext, with a distinct OwnerPassword this
    time. (#​211)

  • PdfDictionary lookup is no longer quadratic in the key count. Set and TryGet now build a
    hash index once a dictionary passes 16 entries, rather than scanning the whole entry list on every
    call. The /Encrypt dictionary is parsed, and copied again by EncryptionSetup.DereferenceValues,
    before any password is checked, on a file anyone can send, so a hostile document naming tens of
    thousands of keys there previously cost time quadratic in that count with nothing to show for it:
    opening a fixture with an 80,000-key /Encrypt dictionary took about 27 seconds before this fix and
    well under a second after. EncryptionSetup's /CF cap (MaxCryptFilters, still 64) keeps its
    comment but loses the reason it used to give: every term that touches /Encrypt is linear now, so
    the cap no longer bears any of the weight of bounding this cost. It stays because a real document
    names one or two crypt filters, not sixty-four. (#​208)
    ... (truncated)

2.1.0

Breaking changes

  • A password-protected document now reaches PdfPreflight as PdfPasswordException, which no
    existing catch covers.
    Every prior version threw UnsupportedPdfFeatureException, and so
    NotSupportedException, for any /Encrypt at all, so that is what a caller of
    PdfPreflight.Validate or PdfPreflight.DetectClaimedProfiles wrote to detect an encrypted file.
    Both are Stable API in a Stable package, and both now open an encrypted document whose empty user
    password suffices, and throw PdfPasswordException for one that needs a non-empty password. That
    exception derives from Exception directly, and deliberately so: a document the reader
    understands but was not given the credentials for is not an unsupported feature. An existing
    catch (NotSupportedException) around either method therefore lets it through. Catch
    PdfPasswordException beside it. (#​97)

  • PdfDocument.DocumentId now throws ArgumentException for a value that is not 16 bytes.
    Previously any other length was accepted and then written as no /ID at all — silently. ISO
    32000-2 Table 15 requires /ID once /Encrypt is present, so on an encrypted document that
    produced a file qpdf rejects outright ("invalid /ID in trailer dictionary"), with nothing to tell
    the caller which value caused it. On an unencrypted document the old behaviour merely omitted an
    optional entry, so code that set a wrong-length id and relied on that omission now sees an
    exception. DocumentId is Stable API, which is why this is recorded here rather than under
    Fixed. (#​97)

Added

  • A committed corpus of encrypted PDFs, one per standard-security-handler /V+/R combination.
    Generated once with qpdf and committed rather than shelled out for at test time, so the corpus is
    byte-identical on CI and locally and leaves no silently-skipped gate. A guard test pins each fixture
    by SHA-256 as well as /V, /R and /CFM: qpdf refuses to write RC4 without --allow-weak-crypto
    and still leaves a zero-byte file behind, and two fixtures are both /V 4 /R 4, differing only in
    the cipher — neither an existence check nor a /V+/R check would notice either. Groundwork for
    the decrypt side. (#​99)

  • Hand-written RC4 and MD5 primitives for the legacy (/V 1–2) decryption path. Internal only —
    no public surface yet, no reader wiring, no security handler; that is a separate change. The BCL
    has never shipped RC4, and its MD5 type defers to the OS crypto library everywhere except Browser
    WASM, where MD5 is unsupported outright, so decrypting an old PDF under Blazor WASM would otherwise
    be a dead end. PdfDocument's /ID generation (ISO 32000-2 §14.4) now goes through this MD5 too,
    in place of the BCL call it used before, so the codebase is actually clear of CA5351 (flags MD5 as
    weak) rather than clear of it only on the new, not-yet-wired decryption path — and Browser WASM
    document writing, not just decryption, no longer depends on a platform MD5 that isn't there. RC4 is
    verified against all three vectors in draft-kaukonen-cipher-arcfour-03 Appendix A, including the
    309-byte vector that runs the keystream past its first 256-byte cycle; MD5 against the full RFC
    1321 §A.5 suite plus a length sweep across the padding and block boundaries, and a differential
    sweep against the BCL. /ID itself is pinned by a known-answer test, because nothing else
    pinned it: every golden document sets its own id, and the computed one folds in a millisecond
    timestamp, so no snapshot could cover it. Groundwork for the decrypt side. (#​97)

  • The decrypt side of the Standard security handler, covering every /V+/R combination the
    committed corpus (#​99) exercises: /V 1//R 2 (RC4-40) through /V 5//R 6 (AES-256).

    Internal only: no public surface, no PdfReader wiring, no /Encrypt gate; a decrypting reader
    ... (truncated)

2.0.0

The first major version since 1.0. Every package moves to 2.0.0 together, as usual.

Two things made a major version necessary: assemblies are strong-named, which changes their
identity, and the analyzer that was supposed to be locking the public API is now actually
locking it, which meant fixing the defects in that surface while doing so was still free.
Most of the rest is work that had to land before the surface froze.

Read Upgrading to 2.0 first if you bind to an assembly
identity by hand
— a PackageReference needs no change, but a binding redirect, an
InternalsVisibleTo, or an Assembly.Load string does.

Breaking changes

Assembly identity

  • All eight packages are strong-named (eng/VellumPdf.snk), with public key token
    b2757187a6d18ae5. AssemblyVersion is pinned to 2.0.0.0 for the whole 2.x line, so
    servicing releases will not force another rebind. (#​53)

Public API

Change Was Now
PdfSignature.ByteRange int[] ReadOnlyMemory<long> (#​178)
PdfLinkAnnotation.Flags int PdfAnnotationFlags (#​176)
TextEncodingWarning character char System.Text.Rune (#​177)
CcittImageLoader.Load two overloads, four positional knobs one overload taking CcittOptions (#​177)
PdfPreflight.Validate(PdfDocumentReader, PdfConformance) public internal (#​176)
HttpRevocationClient(HttpClient, TimeSpan) both arguments required both optional, matching HttpTimestampClient (#​177)
PdfSignatureSettings.SubFilter any string accepted only ETSI.CAdES.detached and adbe.pkcs7.detached (#​176)
SignaturePlaceholderOptions.SubFilter any string accepted the same two values

Each is explained under Added, Changed, or Fixed below.

Behaviour

  • A PAdES signature no longer carries a CMS signing-time signed attribute. ETSI
    EN 319 142-1 admits only the signed attributes its table 1 lists, and signing-time is not
    among them — PAdES conveys the claimed time in the signature dictionary's /M, which this
    library already wrote from the same value. Emitting it anyway held every signature at
    PAdES-BES instead of PAdES-BASELINE-B. Code reading signing-time out of SignerInfo on a
    signature written with the default /SubFilter ETSI.CAdES.detached will no longer find it;
    /M still carries the value, and adbe.pkcs7.detached keeps the attribute, since it makes
    no ETSI claim. (#​170)
  • A tagged document with no tagged content now emits /StructTreeRoot. Setting
    Tagged = true and drawing nothing previously produced no structure tree at all, which
    failed PDF/A-2a and PDF/UA-1 validation. Tagged now means tagged. (#​120)
  • A certificate with a non-minimally-encoded serial is rejected up front on the
    in-process signing paths, with a message naming the offending bytes and the way forward,
    instead of an opaque ArgumentException raised from inside the BCL's CMS encoder. The
    ... (truncated)

1.11.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.10.0...v1.11.0

1.10.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.9.0...v1.10.0

1.9.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.8.2...v1.9.0

1.8.2

What's Changed

Full Changelog: Tim81/VellumPDF@v1.8.1...v1.8.2

1.8.1

What's Changed

Full Changelog: Tim81/VellumPDF@v1.8.0...v1.8.1

1.8.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.8...v1.8.0

1.7.8

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.7...v1.7.8

1.7.7

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.6...v1.7.7

1.7.6

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.5...v1.7.6

1.7.5

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.4...v1.7.5

1.7.4

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.3...v1.7.4

1.7.3

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.2...v1.7.3

1.7.2

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.1...v1.7.2

1.7.1

What's Changed

Full Changelog: Tim81/VellumPDF@v1.7.0...v1.7.1

1.7.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.6.0...v1.7.0

1.6.0

What's Changed

Full Changelog: Tim81/VellumPDF@v1.5.6...v1.6.0

1.5.6

What's Changed

Full Changelog: Tim81/VellumPDF@v1.5.5...v1.5.6

1.5.5

What's Changed

Full Changelog: Tim81/VellumPDF@v1.5.4...v1.5.5

Commits viewable in compare view.

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

---
updated-dependencies:
- dependency-name: VellumPdf.Layout
  dependency-version: 2.3.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added .NET Pull requests that update .NET code dependencies Pull requests that update a dependency file labels Sep 2, 2026
@dependabot @github

dependabot Bot commented on behalf of github Sep 2, 2026

Copy link
Copy Markdown
Author

Superseded by #56.

@dependabot dependabot Bot closed this Sep 2, 2026
@dependabot
dependabot Bot deleted the dependabot/nuget/dependencies/VellumPdf.Layout-2.3.0 branch September 2, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants