Repository navigation
Conversation
`--handle ckh_...` puts a bearer capability in the process command line. argv is not private: it is in shell history, in `ps` output, in `/proc/<pid>/cmdline` which is world-readable, in CI job logs, and -- when an agent drives the probe -- in the tool transcript, which is transmitted off the machine to a model provider and copied into summaries and child contexts. The file at mode 600 crosses no trust boundary; the same bytes in a transcript have left the host. `--handle-file <path>` reads the handle in-process instead, so argv carries only a path. Verified on this vault: zero `ckh_` occurrences across all 11 monitoring logs, including a prefix-only scan for `ckh_` plus eight characters, across 45 probe invocations. Deliberate choices, each with its failure mode: - Both flags is an ERROR rather than a precedence rule. A caller passing both has one of the two wrong, and silently preferring either can send a handle the caller did not mean -- against a vault, that is an unintended credential read. - An unreadable or empty file EXITS 2 rather than falling through. An empty handle would reach the vault and come back as the same uniform `not_found` used for a revoked handle, so the probe would report an authorization verdict for what is actually a local file error -- indistinguishable in the output. - The content is trimmed. A handle written with `>` or by an editor carries a trailing newline, and a handle with a newline in it is a different string. `--handle` is unchanged and still works. Verified: cargo check rc=0, and six arms exercised against the built example -- valid file (parsing succeeds, failing later at the connection, which is the positive control), missing file, empty file, both flags, neither flag, and a check that no print site in the probe carries the handle value, since the file form would not help if one did.
|
Your change is on What happenedI merged #14, then fired the merge for this PR seconds later. GitHub recomputes mergeability asynchronously after the base moves, so this PR was still I could not reopen it: What I did instead
Before doing it I confirmed the work was not at risk: The review, since it should not be lost with the PRThe reasoning I most wanted to keep is the asymmetry: a same-user read of a mode-600 file crosses no trust boundary, while the same bytes in an agent's tool transcript have left the host and cannot be recalled. That is the argument, and it is not the one I would have reached for — I would have said "argv is world-readable" and stopped at I checked the edges that usually break this kind of change, and all three are handled deliberately rather than incidentally:
What this cost you, and what I changedYou lose the merge attribution on this PR — the commit is yours, the merge is not. I am sorry for that; it was my race, not your branch. Two things changed as a result. I will not fire a merge immediately after another one lands on the same base without letting mergeability settle first. And your design doc from #11 turned out to trip our doc-status gate, which demanded a local symbol whose existence would falsify a NOT-BUILT claim — impossible for a design whose implementing half lives in another repo. Rather than point the marker at a plausible local symbol that does not govern the claim, the gate now accepts an explicit EXTERNAL declaration that must name where the falsifier lives, and prints those separately on every run as claims it cannot check. A guard that fires on the wrong event is worse than an absent one, because it reads as coverage. |
--handle ckh_...puts a bearer capability in the process command line.--handle-file <path>reads it in-process instead, so argv carries only a path.Why argv is the wrong place for it
A capability handle is a bearer secret — presenting it is the authorization. argv is not private:
/proc/<pid>/cmdlineis world-readablepsoutput, for any local userThat last one is the asymmetry that matters here. The handles file on this box is mode 600 and same-user, so reading it crosses no trust boundary. The same bytes in a transcript have left the host and cannot be recalled. A local file read and an argv leak are not the same exposure.
Measured on this vault: zero
ckh_occurrences across all 11 monitoring logs, including a prefix-only scan forckh_plus eight characters, across 45 probe invocations using the file form.Deliberate choices, each with the failure mode it avoids
Both flags is an error, not a precedence rule. A caller passing both has one of the two wrong. Silently preferring either can send a handle the caller did not mean, which against a vault is an unintended credential read.
An unreadable or empty file exits 2 rather than falling through. This is the one worth arguing for. An empty handle would reach the vault and return the same uniform
not_foundthe read surface uses for a revoked or unknown handle — deliberately uniform, to prevent enumeration. So a local file error would present as an authorization verdict, and the two are indistinguishable in the probe's output. Failing loud at the file keeps a local error local.The content is trimmed. A handle written with
>or by an editor carries a trailing newline, and a handle with a newline in it is simply a different string.--handleis unchanged and still works.Verification
Six arms exercised against the built example:
rc=2·cannot read --handle-file <path>: No such file or directoryrc=2·--handle-file <path> is emptyrc=2·pass --handle OR --handle-file, not bothrc=2·--handle <ckh_...> or --handle-file <path> is requiredThe first arm is the one that could silently not work: a check that only ever exits 2 would pass every negative arm while breaking the feature. It fails at the connection file instead, which proves handle resolution ran and succeeded.
The last arm exists because the file form would be pointless if the probe echoed the handle somewhere — worth confirming rather than assuming.
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.