cap-dotnet exists to be a security boundary, so a bug that breaks the boundary is not an ordinary bug. This file says what counts, how to report it, and what we will do.
The precise statement of what is and is not promised lives in docs/threat-model.md. Please read §5 ("Explicit non-goals") before reporting — several things that look like escapes are documented limits, and one of them (cap-dotnet is not a process sandbox) is the single most common misunderstanding.
Please do not open a public issue for a suspected sandbox escape.
Use GitHub's private vulnerability reporting on this repository (Security → Report a vulnerability), which opens a private advisory visible only to maintainers. It is the only reporting channel; there is no security mailbox.
A useful report contains:
- the platform, OS version, and filesystem (
ext4,APFS,NTFS,overlayfs, tmpfs…); - on Linux, whether
openat2was in use — the fallback resolver has a documented residual race thatopenat2does not (threat model §6.1), and which path you hit changes the severity; - the sequence of
Diroperations, and the on-disk layout they ran against; - what was reached, and how you confirmed it was outside the sandbox. Device and inode
numbers (
st_dev/st_ino, orVolumeSerialNumber+FileId) are the right evidence — a path string is not, because a path can look outside while naming something inside.
- Reaching, reading, writing, creating, deleting, or renaming any filesystem object not reachable by descending from the sandbox root.
- Learning whether a file outside the sandbox exists, including by distinguishing error codes or timing.
- Any way to obtain a
Dir,CapFile, or handle with wider authority than the one it was derived from. - A crash, hang, or unbounded resource consumption triggered by attacker-controlled path input or attacker-controlled on-disk link structure.
- Anything that causes the API to be silently less contained than documented — for
example, a capability probe that fails open, or an
openat2demotion to the fallback that goes unreported (threat model §6.5).
That last one is worth emphasising: a change that makes containment weaker without failing loudly is treated as a vulnerability even if no escape has been demonstrated.
- Ambient
System.IOuse by the calling application. cap-dotnet does not, and cannot, prevent this (threat model §5.1). - Attacks requiring root,
CAP_SYS_ADMIN,SeBackupPrivilege, or control of the sandbox root's ancestors (§5.2). - Resource exhaustion — filling the disk or the inode table from inside the sandbox (§5.3).
- Hardlinks to outside files that already existed inside the sandbox before the
Dirwas opened (§6.3). - Redirection to a different object inside the same sandbox via a concurrent rename on a
non-
openat2backend. This is the documented residual TOCTOU window (§6.1). Reports that measurably widen the window, or that escape the sandbox entirely, are in scope.
If you are unsure which side of the line something falls on, report it privately. We would much rather triage an out-of-scope report than miss an in-scope one.
| Acknowledge the report | within 3 working days |
| Initial assessment (in scope? severity?) | within 10 working days |
| Fix or a published mitigation | within 90 days of acknowledgement |
We will credit reporters in the advisory unless asked not to, request a CVE for confirmed escapes, and publish a GitHub Security Advisory when the fix ships.
Pre-1.0, only the latest released version is supported. Note in particular that a containment fix may change behaviour in a patch release. Code that depended on an escape working was depending on a bug. The versioning policy, and how to check that a package was built by this repository's CI, are in docs/releasing.md.
The adversarial escape corpus and the TOCTOU stress harness are the primary defence here, and they are public. If you find an escape, the fix is expected to land together with the test case that would have caught it.