sharness.ai / security / hardening · this page as markdown

Hardening

Status: guidance, as of 25 Oct 2026. Two halves. The first is for whoever runs sharness-ai today: how to get the most from a tool that confines one child process, and what it will not do for you however it is run. The second is the lock-down list for the project itself: the repositories, the accounts, the release path and this site, split into what is already in code and what only a person can set in GitHub or PyPI. Dinis Cruz works through the second half; each item is a checkbox because the state cannot be read from the repository and must be confirmed by hand.

1. Running sharness-ai today: what it is, in one paragraph

sharness-ai run forks a child, applies a v0 Process Behaviour Policy to it with Landlock, a network namespace, rlimits and cgroups, and runs your command inside. For the child it is a Boundary; for the process that ran it, it is a Setting it could have skipped. It refuses to run when the policy's hash is not the one you supplied, when a writable path is a symlink to somewhere else, and when a row of the policy cannot be enforced on this kernel. It says, every run, what nothing covers: Unix-domain sockets by path, the environment the child inherits, UDP when no namespace could be made. Everything below follows from that paragraph.

2. How to run it so it holds as much as it can

DoWhy
Supply --expect-hash with a hash you computed yourself, from the policy file, with sharness-ai policy hash on your machine or the browser mockup; never one you read off an agent's outputthe hash is the one thing that comes from outside the agent. Read back from the agent, it comes from the agent (Threat model §3)
Run sharness-ai probe first and read the reading lineit says what this environment grants before any policy: root or not, Landlock ABI, whether a namespace can be made, whether cgroups are writable. The policy can only narrow that
Run sharness-ai policy check and read the advicethe hash names the policy and does not judge it; the advice lines are the known ways a well-formed policy grants more than its page suggests
Write real paths, normalised, no .., no trailing slash, and name the real directory rather than a link to itthe kernel binds inodes; the page must say what the kernel binds. check refuses the first three; run refuses a writable link
Keep write and exec apart. A writable path is never executable under run; do not list the workspace under exec, and run scripts as python3 /work/x.py, never ./x.sha dropped file that can run is the oldest hole there is. Note the limit: an interpreter on the exec list runs code from a writable path; only sharness.bash and the dual-LLM split answer that
Prefer network: "none"; when you need a port, know that v0 names ports and not hostsany host on 443 is still any host. sharness.net is the designed answer; until then the policy is honest about it
Do not pass --best-effort by habitit turns a refusal into a line on stderr and runs anyway. Use it when you have read the line and accept it for this run
Mind the environment. Before run, unset what the child does not need (env -i, or an allowlist)v0 has no row for it and the child sees everything (SR-11)
Mind Unix sockets. If a Docker socket, an X server or a local server listens by path on this machine, the child can reach itLandlock has no rule for them (SR-08). A separate uid, or a mount namespace, is the answer today
Give the child a uid that is not yours where you can (setpriv, a service user), and run as root only where a cgroup must be madeDAC becomes a second layer; RLIMIT_NPROC only binds a non-root uid
Read hello's not covered and caveat lines as part of the result, and treat a ? (inconclusive) as not measuredthe result is only as good as what it says it did not test
Install from a release or a named commit, never a moving branchpip install sharness-ai==<version>, or the repository at a commit; the site's immutable release paths carry every release with its hashes

What no amount of care changes: a policy applied by the agent to its children is a Setting for the agent. The launcher above the agent (E06 and after) is the design's answer and nothing on this page is a substitute for it.

3. The repositories and the accounts: settings only a person can change

Everything a repository can carry is on dev of both repositories as of 25 Oct 2026: pinned actions, minimal permissions, the security workflows, Dependabot, SECURITY.md, the gate. The items below live in GitHub's and PyPI's settings and must be set by an account owner; the review could not read them, so each is a thing to set and then confirm. The weight says what is at stake.

The organisation (SHarness-AI)

Both repositories

The CLI's release path (PyPI)

This site (GitHub Pages)

Agents that work in these repositories

4. What this page does not promise

A hardened repository is not a hardened harness. The list above protects the project's own supply chain; the product's security is the design's, and the design is at the experiments stage. The register on Known risks is where the two meet.