# Sanitization scan result (SC-013) **Status**: PASS **Date**: 2026-08-20 **Task**: T113 **Scanner**: [tests/Test-Sanitization.ps1](../../../tests/Test-Sanitization.ps1) **Files scanned**: 156 ## What is scanned `git ls-files --cached --others --exclude-standard` — tracked files **and** untracked files that are not gitignored. The original scanner walked `git ls-files` alone, which covered only tracked files. That made the gate useless where it matters most: a leaked identifier in a file that has not been committed yet is precisely the one worth catching, and scanning only what is already in history means the scan passes right up until the commit that makes it too late. At the time this was found, the scan was covering 34 of the repository's 156 files and none of the implementation written in this phase. `--exclude-standard` keeps gitignored build output and local scratch files out, so the scan covers exactly what a commit would add. ## Patterns | Pattern | Exemptions | | --- | --- | | GUIDs | Placeholder-shaped GUIDs (`00000000-0000-0000-0000-0000000000a0`); the module manifest's own `GUID =` identity line | | Email addresses and UPNs | RFC 2606 / RFC 6761 reserved domains: `example.com/net/org`, `.invalid`, `.test`, `.localhost` | | `onmicrosoft.com` domains | none | | JWT and bearer-token shapes | none | | Assigned secret, password, or key literals | none | | PEM private key blocks | none | Two exemptions were added during this scan, both narrow and both for things that cannot be replaced with a placeholder: **Reserved domains.** `alex.employee@example.invalid` is guaranteed by RFC to be unresolvable. Rejecting reserved domains would push fixtures toward addresses that merely *look* fake, which is worse — the difference between "obviously synthetic" and "probably nobody's" is the entire reason the reserved list exists. **The module manifest GUID.** A PowerShell module manifest must carry a genuine unique GUID as its identity; it is what distinguishes this module from another of the same name. It identifies the module, not a tenant. The exemption is **line-level** (`^\s*GUID\s*=`), not file-level: exempting the whole manifest would let a real identifier land anywhere in it. ## Verification of the scanner itself A negative control was run: a scratch file containing an email address on a real-world commercial domain and a randomly generated real-shaped GUID was added to the working tree **without** committing it. The scan failed with two findings and named both, by file and line. The file was then removed and the scan returned to PASS. The offending values are described here rather than quoted, because quoting them would make this record itself a finding — which the scan promptly demonstrated when an earlier draft did exactly that. That is the control working. Without a negative control, a scanner that had silently stopped matching would report the same green result as one that is working. ## Result ``` Sanitization scan passed: no tenant data, credentials, or real identifiers found. ``` ## Standing obligations This is a point-in-time result, not a property of the repository. The scan is **gate 1** of [pipelines/validate.yml](../../../pipelines/validate.yml) and runs before every other gate on every pull request — deliberately first, because a leaked identifier is a problem whether or not the code compiles, and every later gate prints file contents into build logs. Runtime audit records legitimately contain real UPNs and Object IDs, which are approved for logs. No such value may ever be committed. When attaching evidence to a verification record (V-1, V-2, V-3), redact identifiers to placeholders first.