SIS CLI
Content Disarm & Reconstruction (CDR) Guide
Status in 0.70.0
Sanitisation is a preview. sanitize plan and sanitize apply cover selected formats only, and apply is not a guarantee that active or embedded content is removed (a PDF’s embedded-file data can survive an apply). sanitize release needs the isolated worker executable, which is shipped beside sis in the release archives. HTML and SVG sanitisation are Unsupported in 0.70.0; scanning them is unchanged. There is no directory-pipeline gateway command in this release.
CDR produces selected sanitised derivatives with removal and residual-risk evidence. A changed file is not automatically safe to release. Preview, transformation, verification and a policy-governed release are distinct operations; support varies by format and environment.
Preview
sis sanitize plan sample.docx
sis sanitize plan bundle.zip --asset '**/[format=pe]'
The first prints the proposed whole-document transformation and residual forecast. The second previews dropping matched member subtrees and their attributed findings; it changes no bytes. Scoped planning refuses a root match and roots with no members. It does not implement a scoped byte-level rebuild. A member the selector cannot decide (it tests a field the member never recorded, such as [role=payload] on a member with no role) is planned for removal as if it matched, and the plan reports unknown_treated_as_matched. See sis docs asset-graph.
Format support
Transformation support is two-state (Supported / Unsupported). HTML and SVG are both
Unsupported in 0.70.0. The sanitisers exist, but the proof that a derivative is safe does not
yet hold for every admitted construct, so HTML and SVG are refused. They are planned for a later
release. An SVG document is refused outright by the proof, and an HTML derivative is refused with
the same class of reason. This is an availability decision, not a loss of analysis: scanning
HTML/SVG is unchanged. Formats without a sanitiser are refused with a clear reason.
Produce a derivative
sis sanitize apply sample.docx --out clean.docx --report-json transform.json --verify-rescan
apply builds the transform plan under the strict-gateway profile (the same default as
sanitize plan; apply has no profile or plan flag), writes a derivative only when the plan was
fulfilled, and re-scans it to prove that. It does not decide releasability. --safe-rebuild
requests reconstruction where supported. A PDF whose trailer has no resolvable /Root is refused:
the command exits non-zero with the structural reason and writes no --out. An encrypted PDF is
also refused (exit 60, no --out); empty-password decryption is not attempted. A PDF that passes
the structural allowlist is rebuilt from that walk: orphan objects and keys outside their context
are removed, and the transform report records each dropped path. A disallowed stream inside a
resource map, appearance, annotation, form field, output intent or /PieceInfo is refused before
the strip, because the strip could otherwise remove the key and erase the evidence. The same PDF as
an archive member is dropped from the archive, not carried through verbatim. The transform report
carries plan_fulfilled and unfulfilled_classes; if any class the
plan promised to remove survives (or the output cannot be re-scanned while the plan declared
removals), apply writes the report, prints a loud plan_fulfilled: false line, does not write
--out, and exits 60. A file already at --out from an earlier run is left untouched, not removed;
treat the exit status as the verdict, not the file’s presence. The derivative
also keeps apply’s strip-everything baseline, so the plan can add removals but never weaken them.
Check the transform report, omissions, format limitations and residual findings before adopting the
output; verify-rescan is not proof that every risk was measured.
Isolated release
sis sanitize release sample.docx --out released.docx --report-json evidence.json --profile cdr-business-docs
release uses an isolated worker and decides in the trusted parent. It publishes --out only when the result is releasable under the selected profile. Supported profiles are cdr-strict-gateway (default), cdr-business-docs and cdr-ai-ingestion. Process isolation requires a supported native environment and the matching worker executable. A failure must never be interpreted as release or replaced with the original input. Publishing forces the full strip floor (scripts, macros, external relationships, embedded content) whatever the plan declares; a plan may add removals, never narrow the floor. An encrypted PDF is refused (exit 60, nothing published); empty-password decryption is not attempted. Every publishing profile removes /EmbeddedFile streams and /EmbeddedFiles trees structurally, regardless of what detection found. PDF 2.0 /AF associated files are removed with their file specifications and streams. Unknown streams under unrecognised keys are removed by the PDF strip path; the structural allowlist independently refuses anything reachable only through a key not allowed for its context. Before publishing, release parses a top-level PDF derivative and refuses (exit 60, nothing published) if any embedded-file stream, /EmbeddedFiles tree or /EF//RF pointer remains — even if the findings say the document is clean. It also walks the derivative from trailer /Root with the structural allowlist. An admissible derivative is rebuilt from that walk: only allowed objects are written, keys outside their context are removed, and unreached objects are dropped and recorded. An object or stream that still reaches through a key not allowed for its context is refused (exit 60, nothing published), and the reason names the path; a wrong-context stream inside a resource map, appearance, annotation, form field, output intent or /PieceInfo is refused on the raw input, before the strip can remove the key. For OOXML, a part survives only when its declared content type and the relationship type that reaches it are allowlisted and its bytes sniff consistently; CFB/OLE, nested ZIP/OOXML, PDF, PE/ELF/Mach-O and script content are dropped whatever the name or declaration. Ambiguous packages (case- or percent-equivalent part names, more than one main part, missing content-type coverage) and non-allowlisted field instructions (DDE, INCLUDETEXT, LINK, an unknown keyword) are refused or neutralised; a field’s result text is kept. A second OOXML sanitise pass replaces the previous manifest, so it does not create duplicate entries. Inside an archive, every PDF member is structurally checked and a member with a survivor is dropped (the parent re-walks the archive as a backstop); see Scope. An EML that keeps any attachment the email lane did not sanitise is refused (exit 60, nothing published) until recursive sanitise-then-reattach lands. MHT/MHTML and any format without a CDR sanitiser are refused with a clear reason. An unfulfilled transform plan is refused the same way.
| Exit | Meaning |
|---|---|
| 0 | Released |
| 20 | Manual review |
| 30 | Quarantine |
| 40 | Reject |
| 50 | Isolation failure |
| 60 | CDR refused the derivative (unfulfilled plan, structural survivor, or unsupported format); nothing was published |
Other nonzero exits can indicate usage or execution failure. These numbers are specific to the sanitize subcommands, not a shared severity ladder across CLI commands. Preserve the evidence report and act only on the actual decision.
Check release evidence
sis sanitize verify evidence.json --input sample.docx --output released.docx
The report is a positional argument. Verification checks evidence consistency and supplied artefact hashes; it does not re-scan content. --evidence renders a summary instead of hash verification. A missing or invalid report fails and is not release approval.
Scope
Document transformations are selected implementations, not universal CDR. PDF, Office, RTF and archive handling differ in what can be removed or rebuilt; consult the actual plan/transform result for support and omissions. A recognised container does not imply its encrypted or unsupported members can be materialised. Archive members whose child sanitiser errors are dropped and recorded, never preserved verbatim; PDF members are also structurally checked and a member with an embedded-file or allowlist survivor, or a wrong-context raw carrier, is dropped. A PDF derivative with an object or stream reachable only through a non-allowlisted structural key is refused rather than published. OOXML parts are allowlisted by relationship type, content type and byte sniffing; embedded/nested packages are dropped, ambiguous packages are refused, and non-allowlisted field instructions are removed with their result text kept. A second OOXML sanitise pass replaces the earlier manifest rather than duplicating it. Under publishing, members past the nesting cap are dropped (depth_cap_exceeded) and members in a format with no sanitiser are dropped (unsupported_member_format); benign siblings are kept. An EML attachment the email lane cannot sanitise is refused rather than published. MHT/MHTML has no CDR sanitiser and is refused. Keep the original and derivative identities separate.
Related guides
sis docs assess— AI-ingestion recommendations and consumer policysis docs extract— text derivatives instead of document reconstructionsis docs formats— operation and format distinctions