security
LeastGrant is not a sandbox
It is a decision layer. It answers a question your agent asks it, and the agent is what enforces the answer. It does not confine a process, intercept syscalls, or contain anything already running. If that is what you need, you need a sandbox, and LeastGrant is not a substitute for one.
If the hook crashes, times out, or exits non-zero, Claude Code treats that as a non-blocking error and runs the tool call anyway. That is the hook contract, not a design choice. LeastGrant is a reliable veto and a best-effort grant, and the whole thing is built around that asymmetry: a crash costs you protection for one call, not your workflow.
reporting
Found a way through?
The definition here is narrower and blunter than most:
a vulnerability is any input that causes LeastGrant to return allow for
an action that should have been asked about or denied. It does not matter how
contrived the input looks or how it got there.
There is deliberately no email address. An address nobody monitors is worse than no address at all, and an advisory reaches the same place with a record attached. If the finding is that LeastGrant is too cautious, that is a normal issue and it is wanted — it just does not need to be private.
What to include
- The exact input. For a shell command, the literal string, not a description of it.
- The output of
leastgrant check "<that input>", and what you expected. - Your posture — the answer differs between
assist,autopilotandstrict. - Your platform. Path handling and the credential-path table differ across Windows, macOS and Linux.
what is actually tested
Evidence, and what it is worth
These are the checks that run on every commit. They are the reason to believe specific claims, not a reason to believe the whole thing is safe. Nothing here says "unhackable"; the point of the list is that each line is something you can go and read.
The measurements, with their caveat attached
The shell parser accounted for 6,054 of 6,057 real agent commands with 0 crashes and 0.03 ms average parse time. Of those, 44.5% are ones LeastGrant will say it fully understands; the rest contain inline code, a script file or a program it has no knowledge of, and always ask.
Those figures come from one developer's machine and one month of work — a sample of one, and a property of that command mix as much as of LeastGrant. They are here because a tool that hides its own hit rate is hiding the thing you need to decide with. Re-derive them on yours rather than taking them from a website.
the honest list
What it does not defend against
A short version. The threat model is 8 sections and does not flatter the design; it includes the adversarial model for the learning itself and what the v0.2.0 audit left standing.
- Anything already running. Once a command is approved, LeastGrant has no
further say. Approving
npm testapproves whatever the test script does. - Code it cannot read. It can see that a script will run. It cannot see
what is in it — which is why
curl | shalways asks instead of being classified. - A compromised machine. State is plain text in your home directory. An attacker who can already write there has better options than editing a permission profile, but it is worth being clear that nothing is sealed.
- Its own opinions being wrong. The classification knowledge is exactly that — opinion. It lives in readable modules so you can disagree with it and send a patch.
this website
The site itself
A security tool with a careless website is an argument against itself, so this one is built to the same rules the product is.
unsafe-inline nor a nonce.The documentation pages render Markdown from the repository through a renderer that never
emits HTML it did not write: raw HTML in the source is escaped rather than passed through,
and link targets go through a scheme allowlist. That is checked by tests with hostile
payloads, alongside assertions over the built output for leaked paths, unexpected origins and
a policy that has not quietly been widened. The site is in the same repository, under
site/.