Skip to content

Security and Integrity

File integrity principles

  1. Minimize file-surface changes during modify workflows
  2. Validate critical workbook outputs after save
  3. Keep regression tests for high-risk edit paths

Signed OOXML packages

Signature presence is separate from encryption and workbook protection. Workbook.vba_signature_status() reports the effective inner VBA project, including any queued replacement, plus outer OOXML signature artifacts in the loaded source package. Workbook.vba_source_signature_status() reports both scopes from the originally loaded package. Neither API verifies the signature, certificate, signer identity, or trust chain.

Modify mode uses a safe default for outer package signatures:

  • A no-op save copies the source package byte-for-byte.
  • Any queued mutation is rejected before output replacement while package_signature_policy is "reject".
  • Call set_package_signature_policy("remove") before the mutation to opt in to removing outer signature parts, relationships, and content-type metadata.
wb = wolfxl.load_workbook("signed.xlsm", modify=True)
wb.set_package_signature_policy("remove")
wb.active["A1"] = "edited"
wb.save("unsigned-edited.xlsm")

The "remove" policy produces an unsigned output. WolfXL does not create or cryptographically verify digital signatures.

Sanitization and removal verification

wolfxl-ops sanitize and wolfxl.operations.sanitize_workbook remove only the categories a version-1 request names, and they report what they did not remove. wolfxl-ops sanitize-inspect reports the same inventory while writing nothing.

  • The source is read once, bounded by the package admission limits, and the request's source_sha256 is verified against exactly those bytes. The original path is hashed again immediately before the no-replace rename, so a source whose bytes differ at that check refuses with source_changed and publishes nothing. That check observes the path at that instant and claims no more: it cannot guarantee the pathname is unchanged until the rename, and nothing here promises it.
  • The destination directory must not exist and must not resolve to the source. The sanitized bytes are staged privately and published with one atomic no-replace rename, so an existing destination is preserved, an interrupted run leaves no output behind, and only the staging that call created is removed. The workspace records the identity of the directory that call created, and cleanup removes it only while the name still holds that directory, without following a symbolic link; a workspace that was renamed away or rebound, or replaced by a file or a symbolic link, is preserved and the success path refuses before publication.
  • Both commands require a source path and a destination parent directory that the caller controls. The workspace-identity, replacement, and final-source checks detect a concurrent same-UID writer and refuse; they are not a defense against one, and no blanket hostile-namespace guarantee is offered.
  • The published artifact is named and typed from the sanitized package itself, from its workbook main-part content type, so a package whose macros were retained is published as a macro-enabled workbook and never as a macro-free .xlsx; a workbook type outside that admitted vocabulary refuses with unsupported_feature and writes nothing. The source file name and extension never decide either one.
  • A package carrying outer OOXML signature material is never republished with those signatures invalidated: a requested removal that would change such a package refuses with policy_rejected and writes nothing. Strip the signature through the existing save path before requesting a removal. inspect_sanitization reports signature presence from package metadata only; it verifies no signature, certificate, signer, or trust chain, and no signature payload is read.
  • The redacted report is count-only. Recognized categories carry the disposition the caller's own allowlist selected, and every residual category that was not removed carries its own retained entry — media payloads, printer-settings and revision metadata, opaque non-XML payloads, cell data and hidden rows or columns inside retained worksheets, signature scopes, and orphan relationship parts. Those entries state what was retained; they are never a confidentiality statement about the output, and no part name, relationship target, host path, or content value appears in a report.

Reporting an integrity issue

Include:

  • input workbook (or minimal repro)
  • exact code used
  • expected output vs actual output
  • WolfXL version and environment

Safe rollout suggestions

  • Use side-by-side comparison in early rollout stages.
  • Keep fallback path to existing engine until confidence is established.
  • Track regressions explicitly in changelog.