You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while reviewing #354 (FD-rooted bounded opens). Pre-existing and deliberately out of that PR's scope, filed so it is not lost.
What
agent-bridle-core/src/caveat_interceptor.rs:326-330 allowlists /dev/null, /dev/stdout and /dev/stderr using an un-canonicalized string comparison, and evaluates that allowlist before the leash check.
Why it matters
This is the same failure family #354 exists to eliminate: a pathname is treated as identity. A string compare against /dev/null decides authority, but the string is not the object:
A path that string-compares unequal may still resolve to the intended device (/dev/./null, //dev/null, a symlink chain, a bind mount), so the allowlist is not a reliable allow.
More seriously, a path that string-compares equal need not resolve to the real device. Inside a container, a chroot, a mount namespace, or a directory the agent can influence, /dev/null can be an ordinary file, a symlink, or a device the grantor never intended — and because the compare short-circuits ahead of the leash check, the leash never gets to adjudicate it.
Because the allowlist runs first, this is a bypass of the adjudicator rather than a widening of it. AdmittedFence::admit is supposed to be the sole adjudicator; a pre-check that can say "allow" ahead of it is a second, weaker authority path.
Suggested direction
Do not fix by adding more string normalization — that reproduces the bug class. Prefer identity over spelling:
delete the pre-check entirely and let the leash adjudicate /dev/null like anything else, if the grant model can express it; or
if the allowlist must stay for bootstrap reasons, move it after the leash check so it can only ever narrow, never widen.
Acceptance
A regression test where a path that string-compares equal to an allowlisted device resolves to something else, and is REFUSED.
A regression test where a legitimately-spelled variant of the real device is handled correctly under whichever rule is chosen.
The adjudicator ordering invariant stated explicitly: nothing may return Allow ahead of the leash check.
Provenance
Surfaced by the #354 review sweep for validated_path -> string -> open(path) -> authority reconstruction patterns. Not fixed there because #354 is scoped to the fdguard seam and its call-site wiring is #351's second half.
Found while reviewing #354 (FD-rooted bounded opens). Pre-existing and deliberately out of that PR's scope, filed so it is not lost.
What
agent-bridle-core/src/caveat_interceptor.rs:326-330allowlists/dev/null,/dev/stdoutand/dev/stderrusing an un-canonicalized string comparison, and evaluates that allowlist before the leash check.Why it matters
This is the same failure family #354 exists to eliminate: a pathname is treated as identity. A string compare against
/dev/nulldecides authority, but the string is not the object:/dev/./null,//dev/null, a symlink chain, a bind mount), so the allowlist is not a reliable allow./dev/nullcan be an ordinary file, a symlink, or a device the grantor never intended — and because the compare short-circuits ahead of the leash check, the leash never gets to adjudicate it.Because the allowlist runs first, this is a bypass of the adjudicator rather than a widening of it.
AdmittedFence::admitis supposed to be the sole adjudicator; a pre-check that can say "allow" ahead of it is a second, weaker authority path.Suggested direction
Do not fix by adding more string normalization — that reproduces the bug class. Prefer identity over spelling:
dev/ino, i.e. theRootIdentityshape fdguard: open_beneath_* — race-free bounded opens beneath a granted root (#351) #354 introduces in fdguard), not text; or/dev/nulllike anything else, if the grant model can express it; orAcceptance
Allowahead of the leash check.Provenance
Surfaced by the #354 review sweep for
validated_path -> string -> open(path) -> authorityreconstruction patterns. Not fixed there because #354 is scoped to the fdguard seam and its call-site wiring is #351's second half.