sanitize's egress guard cannot see a path under a WSL UNC host, so the "final backstop" claim in diagnostics.py does not hold for that shape.
Measured
A diagnose document containing \\wsl.localhost\Ubuntu-24.04\home\u\p passes sanitize.assert_no_leak and returns []:
leaky = json.dumps({"env": {"raw_project": str(Path(r"\\wsl.localhost\Ubuntu-24.04\home\u\p"))}})
sanitize.assert_no_leak(leaky) # -> []
Two independent causes:
_ABS_HOME_RE (src/bmad_loop/sanitize.py:100) matches /home/, /Users/, /root/ and [A-Za-z]:\Users\. A backslash \home\ under a UNC host matches none of them — and a WSL distro path ends in the Linux username, which is the identifier at risk.
- The username rule compares
getpass.getuser(), i.e. the Windows account. On a native-Windows interpreter reaching a distro path those two names are routinely different, so the rule cannot fire on the one it should.
Compounding it, when the document is rendered via json.dumps every backslash is doubled, so a raw-spelling substring scan over the rendered bytes never matches either — the trap already documented at src/bmad_loop/cli.py:3006-3011.
Why this matters now
Not currently exploitable: after #485, collect_env reduces the path to a boolean (diagnostics.py:295-296) and no EnvInfo field carries it. The problem is that the module docstring at diagnostics.py:14-20 describes the safety model as fail-closed "as a final backstop the rendered bytes are run through sanitize.guard" — and for this shape that backstop provably cannot fire. Any future field that carries a project path would leak the Linux username into a document people paste into bug reports, with the stated last line of defence silently absent. (collect_env's own docstring at diagnostics.py:262-266 states the limit correctly; the module header's blanket claim is the one that overreaches.)
Suggested
Teach the path rules the UNC/backslash form (\\wsl.localhost\<distro>\home\<user>, \\wsl$\..., and the \\?\UNC\ folding is_wsl_unc_path already normalizes at src/bmad_loop/platform_util.py:163), and reconcile the module docstring with what the guard actually covers. A regression test should assert over decoded values rather than rendered bytes, for the escaping reason above.
Surfaced while reviewing #485; the vacuous test assertions that hid it were fixed there in 03ac27e, but the guard's blindness is upstream of that and unfixed.
sanitize's egress guard cannot see a path under a WSL UNC host, so the "final backstop" claim indiagnostics.pydoes not hold for that shape.Measured
A
diagnosedocument containing\\wsl.localhost\Ubuntu-24.04\home\u\ppassessanitize.assert_no_leakand returns[]:Two independent causes:
_ABS_HOME_RE(src/bmad_loop/sanitize.py:100) matches/home/,/Users/,/root/and[A-Za-z]:\Users\. A backslash\home\under a UNC host matches none of them — and a WSL distro path ends in the Linux username, which is the identifier at risk.getpass.getuser(), i.e. the Windows account. On a native-Windows interpreter reaching a distro path those two names are routinely different, so the rule cannot fire on the one it should.Compounding it, when the document is rendered via
json.dumpsevery backslash is doubled, so a raw-spelling substring scan over the rendered bytes never matches either — the trap already documented atsrc/bmad_loop/cli.py:3006-3011.Why this matters now
Not currently exploitable: after #485,
collect_envreduces the path to a boolean (diagnostics.py:295-296) and noEnvInfofield carries it. The problem is that the module docstring atdiagnostics.py:14-20describes the safety model as fail-closed "as a final backstop the rendered bytes are run throughsanitize.guard" — and for this shape that backstop provably cannot fire. Any future field that carries a project path would leak the Linux username into a document people paste into bug reports, with the stated last line of defence silently absent. (collect_env's own docstring atdiagnostics.py:262-266states the limit correctly; the module header's blanket claim is the one that overreaches.)Suggested
Teach the path rules the UNC/backslash form (
\\wsl.localhost\<distro>\home\<user>,\\wsl$\..., and the\\?\UNC\foldingis_wsl_unc_pathalready normalizes atsrc/bmad_loop/platform_util.py:163), and reconcile the module docstring with what the guard actually covers. A regression test should assert over decoded values rather than rendered bytes, for the escaping reason above.Surfaced while reviewing #485; the vacuous test assertions that hid it were fixed there in
03ac27e, but the guard's blindness is upstream of that and unfixed.