LeastGrant

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.

it fails open

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, autopilot and strict.
  • 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.

bypass corpus
6255 allowlist evasions and 7 symlink traversals, each run against an engine deliberately trained with hundreds of approvals for the innocuous prefix. If one is ever auto-approved, the build fails.
test files
26Run on three operating systems across Node 20, 22 and 24, because path containment is exactly where platforms differ.
runtime dependencies
0There is no third-party code in the permission path. A dependency there would be code you did not read, deciding what your agent may do.
fuzzing
randomisedGenerated symlink topologies compared against a reference resolver written independently of the one under test — on Linux and Windows, the two platforms whose link semantics differ most. Path containment is the one place where being wrong is silent.

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 test approves 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 | sh always 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.

third-party JavaScript
0No analytics, no tag manager, no CDN. The page makes exactly the requests its HTML declares, all to this origin.
cookies and storage
noneNothing is set, read, or persisted. There is no consent banner because there is nothing to consent to.
fonts
self-hostedSubset to the glyphs used and served from this origin. A webfont CDN would see every reader of this page.
content policy
no inlineNo inline script or style anywhere in the output, so the CSP needs neither 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/.