Release note · August 4, 2026
A signature declaration needs one home
A package signature can contain several XMLDSIG objects, but OPC distinguishes one of them as the package-specific object. A static coverage audit should not select whichever Manifest happens to be reachable and call the result package coverage. Before interpreting any Manifest declarations, it needs to know that it is looking at the one OPC structure those declarations belong to.
Correction, August 4, 2026: 0.46 established the required package-object and binding topology, but it did not yet validate the required OPC idSignatureTime property inside that object. DocFence 0.47 closes that separate declaration gap by requiring the fixed property ID, target, SignatureTime child shape, and Format/Value lexical agreement before coverage is credited.
One special object, one binding
OPC fixes the package-specific object identifier to idPackageObject and gives that object a narrow direct-child structure. Its package-specific Object rule requires the Manifest and SignatureProperties pair; its SignedInfo rule requires exactly one reference to that object.
ds:Signature
├─ ds:SignedInfo
│ └─ one Reference URI="#idPackageObject"
└─ ds:Object Id="idPackageObject"
├─ ds:Manifest
└─ ds:SignatureProperties
DocFence 0.46 now requires that exact direct topology before its bounded declaration audit credits any Word part or relationship. The package object must have no other attributes; its direct children must be exactly one ds:Manifest followed by one ds:SignatureProperties. A nonstandard identifier, a missing or extra child, duplicate package objects, or duplicate binding references leaves static declaration coverage unavailable. Other application-specific objects can still exist; they are not substituted for the package-specific carrier.
Topology comes before declaration resolution
This closes an ambiguity in the earlier bounded audit. It no longer unions declarations from arbitrary objects or accepts a generic bound Manifest as if it were OPC's package-specific object. Once the topology qualifies, DocFence resolves only that one Manifest with its existing narrow rules for exact part/content-type matches, relationship transforms, canonicalization ordering, digest-child shape, and relationship selectors.
That sequence makes the public signal easier to interpret. An invalid package-object layout is not counted as a partly successful declaration with a few private references attached; it is a signature without declared package coverage. The aggregate report remains path-free and value-free, while DFP092 and DFP093 can enforce the bounded review contract.
Still not signature validation
This is deliberately a structural gate, not an XMLDSIG implementation. DocFence uses the binding Reference's direct URI fragment only. It does not parse or validate that Reference's digest or transforms, decode or recompute manifest digests, execute transforms, verify a signature, inspect a certificate, establish trust, or predict an Office client decision.
version: 1
rules:
require_complete_package_signature_coverage: true
no_package_signature_coverage_changes: true
The policy therefore says something specific and useful: a recognized package signature retains a complete declaration over DocFence's bounded Word scope. It does not say the signature is cryptographically valid, trusted, exhaustive, or effective in a particular Office consumer.
A corrected public benchmark
This change exposed a fixture-quality issue in the package-signature cases of the Document Change Assurance Benchmark. DCAB 0.32.0 normalizes those non-cryptographic XMLDSIG-shaped carriers to idPackageObject. The two pairs retain all 42 cases, public facts, fixture schema, Word text, and review expectations; only their private carrier topology changes. Its independent verifier now pins the standard identifier rather than sharing the builder's choice.
The complete corpus is also available as a public Hugging Face dataset. Its downloaded package-signature fixture was checked after publication to contain both the corrected object and its binding Reference.
Evidence and compatibility
The 67-test DocFence suite covers a missing SignatureProperties child, a nonstandard package-object ID, an extra direct child, duplicate package objects, and duplicate bindings, alongside the prior transform and digest-shape cases. DCAB's complete 42-case adapter passes against the released DocFence wheel.
A fresh wheel and a fresh source-distribution installation both retained complete bounded coverage for the signed content-injection baseline from the public OOXML Signature Security artifacts. The published content-injection, universal-signature-forgery, duplicate-document, and evil-type attacker variants each exposed at least one uncovered or unavailable declaration boundary. This is a compatibility smoke test over stored structures, not a claim that any sample is trusted or safe.
Both release commits and tags passed hosted CI. Source and wheel artifacts were built twice under their committed timestamps and matched byte-for-byte; fresh installations exercised the signed sample and the DCAB adapter. The public GitHub assets were then downloaded and byte-compared with those verified builds.
python -m pip install https://github.com/SybilGambleyyu/docfence/releases/download/v0.46.0/docfence-0.46.0-py3-none-any.whl
docfence check approved.docx candidate.docx --policy docfence.yml --format sarif --output docfence.sarif
The tagged policy reference, threat model, and validation notes define the exact boundary. Good static review starts by refusing to pretend that arbitrary XMLDSIG structure is the OPC declaration it is not.