Release note · August 6, 2026

A content type is not case-sensitive

By SybilGambleyyu · DocFence 0.61.0

An OPC package-signature manifest identifies a stored part with a local URI and a ContentType query value. Those are not the same kind of comparison. The part name is exact; the query value is a media type. DocFence 0.61 now keeps that distinction in its bounded declaration-coverage audit.

The value after ContentType= is a media type

A declaration can look like this:

<ds:Reference URI="/word/styles.xml?ContentType=APPLICATION/XML">
  ...
</ds:Reference>

ECMA-376 Open Packaging Conventions §10.5.7.3 defines the value after ContentType= as the case-insensitive media type of the target part. APPLICATION/XML and application/xml therefore name the same type. Earlier DocFence releases used exact string equality here, so a standards-shaped declaration with only an ASCII case difference could look unresolved.

One rule, three bounded paths

0.61 folds only ASCII AZ when it compares a manifest ContentType value. It applies that rule to ordinary part references, relationship-part references, and the global local-context check that validates an OPC Relationship Transform. The local URI grammar, the ContentType query key, and stored part names remain exact.

This is not a new MIME parser or a broader signature validator. DocFence does not strip parameters, normalize arbitrary Unicode, rewrite a package, execute a transform, canonicalize XML, recompute a digest, verify XMLDSIG, validate a certificate, or make a trust decision. It corrects the one comparison that determines whether its static declaration inventory can credit a standards-shaped reference.

version: 1
rules:
  require_complete_package_signature_coverage: true
  no_package_signature_coverage_changes: true

Evidence and use

The 71-test suite now includes a case-varied ordinary-part media type and a case-varied relationship-part media type. The latter exercises both the manifest resolver and the Relationship Transform local-context boundary. A genuinely different relationship content type remains rejected.

Across the 29 DOCX fixtures in the public OOXML Signature Security artifacts, 21 XML signature parts parse successfully. They contain 152 package-manifest references; 133 are resolvable and all 133 already use the exact stored ContentType spelling. No corpus profile changes from 0.60. Main and tagged CI passed, and the independent Document Change Assurance Benchmark adapter passed against the tagged wheel.

Two independent epoch-fixed builds were byte-identical. Public downloads of the published wheel and source distribution matched those artifacts byte-for-byte. SHA-256: wheel ae079b409cda0dfe6c033d5e16c5e17fa5ae35dfe0359b2969fb88ab7bc72d6b; source distribution 230692c46bfcc69d229b273f8305fd23a5cec1fd48b330a368d584a4c5e924d2.

python -m pip install https://github.com/SybilGambleyyu/docfence/releases/download/v0.61.0/docfence-0.61.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 boundary. A coverage statement should use the comparison rule the package format actually specifies.