Release note · August 1, 2026
The linked Word object hiding in a legacy VML shape
A Word document can carry a linked spreadsheet, chart, or other OLE object as a shape-backed piece of legacy XML rather than as an ordinary field. A generic embedded-object count can say that a package has OLE material, but it cannot tell a reviewer whether the stored marker is a static embed or a source-backed link with an update mode.
DocFence 0.24 adds a narrow, privacy-safe inventory for that direct legacy surface: o:OLEObject Type="Link" in a supported Word story. It is stored-package evidence for CI review, not a Word renderer, OLE client, source resolver, or network monitor.
Linked and embedded are different review questions
Microsoft’s linked-versus-embedded-object guidance draws a practical line: linked data stays in a source file and can change when that source changes, while an embed is a static copy inside the Word file. Both may appear near the same kind of visual placeholder, so a relationship total alone is too coarse for a controlled handoff.
The OOXML model makes the direct distinction available in markup. The Open XML SDK documents o:OLEObject; the ECMA-376 element definition describes its Type, optional r:id, and UpdateMode attributes. Public Word XML fragments show the stored form in ordinary work: an Excel-linked object has Type="Link" and UpdateMode="Always"; another public Word shape example uses UpdateMode="OnCall" and is explicitly not represented as a conventional LINK field.
Count the direct marker; preserve the awkward cases
DocFence scans direct o:OLEObject elements whose unqualified Type is Link across body, header, footer, footnote, endnote, comment, and glossary stories. Duplicates and Markup Compatibility branches remain separate stored markers. The scanner does not select a client branch, associate a marker with a rendered shape, or deduplicate a visual object.
When a marker has r:id, the inventory recognizes the standard OLE-object relationship and reports its stored target mode as external or internal. The Embedded Object Part contract permits both modes. Any other resolved relationship type or mode remains visible as unsupported evidence instead of being relabeled a normal OLE object. A direct marker without r:id is also retained in its own class because the schema permits that attribute to be absent.
The release separately aggregates stored UpdateMode="Always" markers. Every other or absent update value is counted as nonautomatic-or-unspecified. That is deliberately descriptive, not predictive: it says what the package records, not that Word will open a source, refresh data, or honor the flag.
Type="Embed", WordprocessingML w:objectLink, VML image data, VML shape links, DrawingML linked pictures, and broad embedded OLE/package/control payload totals remain separate surfaces. A lone OLE relationship does not create a linked-OLE marker count.
Private semantics, concrete policy gates
Reports expose only aggregate marker/story, update-mode, and relationship-classification counts. Link sources, monikers, program IDs, shape and object IDs, relationship targets and IDs, field codes, VML markup, and story paths never appear in JSON, Markdown, or SARIF.
The private signature retains the full direct marker while normalizing a relationship ID to its stored relationship semantics. That makes same-count source, program, field-code, update-mode, or target rewrites review-visible without churning the inventory when only an ID is renumbered.
For a handoff that must carry no direct linked-OLE marker:
rules:
require_no_word_vml_linked_ole_objects: true
This produces DFP061. A controlled template that intentionally retains approved markers can instead protect its private baseline:
rules:
no_word_vml_linked_ole_object_changes: true
DFP062 detects a material marker-inventory change. These gates add narrow markup context to the existing embedded-object and relationship review; they do not replace either.
Evidence, and the boundary it does not cross
The 50-test release suite covers standard external and internal OLE-object relationships, an unsupported relationship, a marker without r:id, automatic and nonautomatic/unspecified update modes, duplicates, body/header stories, Transitional and Strict namespaces, orphan exclusion, unavailable relationships, source and target rewrites, relationship-ID stability, privacy redaction, and JSON/Markdown/SARIF policy output. It also verifies that Type="Embed" and w:objectLink remain outside this specialized inventory.
Release validation combines that controlled package with the public real XML fragments above. They are marker evidence rather than downloadable whole-package fixtures, so the release does not overclaim a public end-to-end Word-package smoke test for every form. Hosted CI passed on Python 3.11 and 3.13 for the release commit and tag. The wheel and source archive were independently rebuilt from the tagged source with a fixed source date and matched byte-for-byte; fresh public downloads passed checksum and metadata verification, and an isolated installed wheel reproduced the linked-OLE counts without exposing its target, program ID, or field text.
DocFence does not resolve, retrieve, open, update, activate, evaluate, render, or execute an OLE object. It does not establish that Word will honor a marker, that a source is reachable or safe, or that a visible shape is actually associated with it. Use it as a bounded local review signal alongside an appropriate rendering and domain review process.
python -m pip install https://github.com/SybilGambleyyu/docfence/releases/download/v0.24.0/docfence-0.24.0-py3-none-any.whl
docfence profile candidate.docx --format markdown
docfence check approved.docx candidate.docx --policy docfence.yml --format sarif --output docfence.sarif
The public release includes the wheel, source archive, and SHA-256 manifest. The tagged policy reference, threat model, and validation notes define the exact behavior and limits.