Repository navigation
Harden the export sanitizer after adversarial review - #6
Merged
Merged
Conversation
Three independent reviewers ran the script against realistic Graph and portal export shapes and leak-path fixtures. Every confirmed finding is fixed and covered by a test: Serializer - escape by code point: soft hyphens, zero-width and control characters were written as \b because a switch on [char] compares culture-aware - fractional numbers and negative zero normalized; Local DateTime values written as UTC so output does not depend on the host time zone Plumbing - top-level arrays no longer unroll (one-element arrays became objects, [] became null) - relative -OutputPath and -NameMapPath resolve against PowerShell's location instead of the process directory - name map values are validated so a display name cannot break the <GROUP:...> placeholder or smuggle an address into it Coverage - secrets: *SecretSettingValue values, encrypted OMA-URI values and secretReferenceValueId, password/preSharedKey/sharedSecret/*Token keys - composite assignment ids and sourceId, <nav>@odata.context annotations - tenant ids learned from tenantId keys (dashed and dash-less forms) - GUIDs under any *Id, group, user, device, app or filter key, and inside /groups/, /users/, /directoryObjects/ URLs; ADMX definition ids kept - guest (#EXT#), %40-encoded and non-ASCII UPNs; .mail.onmicrosoft.com; SharePoint hosts and /personal/ paths; MAC addresses, UNC hosts, .local/.corp/.internal/.lan hostnames, RFC 1918 addresses - device names, user display names, product keys, thumbprints, base64 payloads and certificates - object keys are sanitized too; a ReviewHints list in the summary points at lines that still carry a GUID or IPv4 for a human to read Guard - stops flagging JSON keys such as definition@odata.bind as addresses - catches secrets in JSON form and under Wi-Fi/VPN key names - matches guest, encoded and non-ASCII UPNs; no longer trusts admin@ on a real domain; checks the real label of .mail routing domains Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NLBetJRtHG4ZgUfj37xGn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
PR #1 merged the first version of
ConvertTo-SanitizedIntuneExport.ps1. Three independent reviewers then ran that version against realistic Graph and admin-center export shapes and leak-path fixtures, and confirmed several defects by execution. This PR carries the single commit that fixes all of them, with a regression test for each.Serializer
switchon a[char]compares culture-aware, so soft hyphens, zero-width characters and control characters were silently written as\b.DateTimevalues are written as UTC so output does not depend on the host time zone.Plumbing
[]becamenull).-OutputPathand-NameMapPathresolve against PowerShell's location instead of the process directory.<GROUP:...>placeholder or smuggle an address into it.Coverage
*SecretSettingValuevalues, encrypted OMA-URI values andsecretReferenceValueId, andpassword/preSharedKey/sharedSecret/*Tokenkeys.sourceId;<nav>@odata.contextannotations.tenantIdkeys (dashed and dash-less forms).*Id, group, user, device, app or filter key, and inside/groups/,/users/,/directoryObjects/URLs; ADMX definition ids are kept.#EXT#),%40-encoded and non-ASCII UPNs;.mail.onmicrosoft.com; SharePoint hosts and/personal/paths; MAC addresses, UNC hosts,.local/.corp/.internal/.lanhostnames, RFC 1918 addresses.ReviewHintslist in the per-file summary points at lines that still carry a GUID or IPv4 for a human to read.Guard (
.github/scripts/Test-RepoSanitized.ps1)definition@odata.bindas e-mail addresses.admin@on a real domain; checks the real label of.mailrouting domains.Type of change
docs/,runbooks/,examples/)artifacts/)scripts/)remediations/)Platform and licensing
Runs anywhere PowerShell 5.1 or 7 runs. No Intune licensing dependency; the script is offline and never connects to Graph.
Testing
Synthetic exports only, on PowerShell 7.6 (Linux): 160 Pester tests pass (31 for the sanitizer, 25 for the guard, the rest structure checks). Still not run against a real tenant export; the
.NOTESblock says so. Windows PowerShell 5.1 compatibility is by construction (no 7-only syntax, two-argumentJoin-Path, parameter probing forConvertFrom-Json), not by execution.Checklist
CONTRIBUTING.md..NOTESblock lists the known gaps the script cannot recognise.exit.Invoke-ScriptAnalyzer -Path . -Recurse -Settings ./PSScriptAnalyzerSettings.psd1reports nothing.Generated by Claude Code