1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# Paths Harn knows by name, grouped by what a confined child may do with them.
#
# Data, not code: adding a path is a reviewable one-line diff, and every
# consumer derives its matcher from this file. `known_paths/mod.rs` parses it
# once, rejects an empty credential list, a credential without a reason, a
# duplicate, and any grant that names a credential or sits inside one.
#
# Entries under `home` are relative to `$HOME`. Class decides authority:
#
# - credential: never readable by a confined child, whatever grants its
# parent. The taint gate, the command risk scan, and the approval rules
# match these anywhere in a path, not only under `$HOME`.
# - package_config: read-only, granted by the PackageManagerConfig preset.
# - toolchain_read: read-only, granted by the DeveloperToolchains preset.
# - toolchain_cache: read+write, granted by the DeveloperToolchains preset.
[]
= [
".ssh",
".aws",
".gnupg",
".netrc",
".pgpass",
".git-credentials",
".docker/config.json",
".config/gh/hosts.yml",
".config/gcloud",
".kube/config",
".npmrc",
".pypirc",
".cargo/credentials",
".cargo/credentials.toml",
".composer/auth.json",
".config/composer/auth.json",
".config/git/credentials",
".config/glab-cli",
".config/hub",
".config/github-copilot",
".config/rclone/rclone.conf",
".config/doctl",
".config/hcloud",
".config/containers/auth.json",
".config/.wrangler",
".config/stripe",
".config/sops/age",
".config/configstore/firebase-tools.json",
".cache/huggingface/token",
".cache/huggingface/stored_tokens",
]
# File names that hold credential material wherever they live. Matched against
# the last path component, case-insensitively. These cannot be sandbox-denied
# (the sandbox denies paths, not names), so they reach the path matchers only.
= [
".env",
".env.*",
".envrc",
"id_rsa",
"id_ed25519",
"id_ecdsa",
"id_dsa",
"*.pem",
# Private keys conventionally end in `.key`. A Keynote document does too;
# a confirmation prompt on one is the cheaper mistake.
"*.key",
"credentials.json",
"secrets.*",
"*.secrets.*",
]
[]
= "private keys and known_hosts"
= "long-lived access keys and session tokens"
= "private keyring"
= "plaintext machine credentials"
= "PostgreSQL passwords"
= "git credential-store tokens in the default layout"
= "registry auth tokens"
= "GitHub OAuth token"
= "Google Cloud credentials"
= "cluster credentials and client certs"
= "registry auth tokens; children get a sanitized stand-in"
= "package index upload credentials"
= "crates.io API token, under preset-granted ~/.cargo"
= "crates.io API token, under preset-granted ~/.cargo"
= "Packagist and GitHub OAuth tokens; under preset-granted ~/.composer"
= "the same tokens in Composer's XDG layout; under preset-granted ~/.config/composer"
= "git credential-store tokens in the XDG layout; under preset-granted ~/.config/git"
= "GitLab CLI tokens (config.yml)"
= "hub CLI OAuth token"
= "Copilot OAuth tokens (hosts.json, apps.json)"
= "remote storage credentials"
= "DigitalOcean API token"
= "Hetzner Cloud API tokens"
= "Podman and Buildah registry auth"
= "Cloudflare Wrangler OAuth tokens"
= "Stripe CLI API keys"
= "age private keys for sops"
= "Firebase CLI refresh token"
= "Hugging Face access token (HF_HOME default)"
= "Hugging Face saved access tokens"
[]
# Measured by scripts/sandbox_config_census.harn. Unknown XDG siblings stay
# closed, and a credential inside any of these is still denied.
= [
".gitconfig",
".yarnrc.yml",
".config/git",
".config/pip",
".config/go",
".config/uv",
".config/pnpm",
".config/yarn",
".config/composer",
".config/rustfmt",
".config/cmake",
".config/gem",
".config/mise",
".config/ruff",
".config/black",
".config/sbt",
".config/coursier/mirror.properties",
".config/swiftpm/configuration",
".npm",
".cache/pip",
".cache/uv",
".cache/node/corepack",
".cache/yarn",
".cache/composer",
".cache/mise",
".cache/black",
".cache/sbt",
".cache/coursier",
".cache/JNA",
".cache/clang",
".cache/org.swift.swiftpm",
".cache/org.swift.foundation.URLCache",
# .cache/go-build and .cache/harn are owned by the writable toolchain_cache
# roots. Repeating them here cancels that grant on macOS, where the
# read-only rules follow the write allows.
".pip",
# Composer's macOS home (`COMPOSER_HOME` default). `config.json` and the
# global `composer.json` are configuration; `auth.json` is a credential.
".composer",
# pnpm's global rc on macOS (`env-paths` config dir). A registry or
# store-dir setting, never a token: those live in `.npmrc`.
"Library/Preferences/pnpm",
".cargo/config",
".cargo/config.toml",
# `.cargo/registry` and `.cargo/git` are deliberately NOT here. They are
# build caches Cargo must WRITE, so they are toolchain_cache entries.
# Listing them here too would re-deny their writes: the macOS backend emits
# a `(deny file-write*)` for every package-config root AFTER the write-allow
# block, and last-match-wins would cancel the cache grant. `.cargo` itself
# stays readable as a toolchain_read root.
]
[]
= [
".asdf",
".bun",
".cargo",
".fnm",
".juliaup",
".local/bin",
".local/share/mise",
".local/share/pnpm",
".local/share/uv",
".nvm",
".pyenv",
".rbenv",
".rustup",
".sdkman",
".swiftly",
".volta",
"Library/pnpm",
"go",
]
# Added on Windows only.
= [
"AppData/Local/Programs/Python",
"AppData/Local/uv",
"AppData/Roaming/uv",
"scoop",
]
# Per-user JVM/iOS/Go/Cargo/Harn caches. Shared across platforms so the macOS
# seatbelt and Linux Landlock backends render the same set; an OS-foreign
# entry is simply absent on disk, and each backend skips a missing root.
[]
= [
".gradle", # Gradle (JVM/Android/Kotlin)
".m2", # Maven (JVM)
".konan", # Kotlin/Native
"Library/Caches/CocoaPods", # CocoaPods (iOS/macOS)
"Library/Developer/Xcode/DerivedData", # Xcode build products
# Go build + module caches. `go build`/`go test` write compiled package
# objects to GOCACHE and downloaded modules to GOMODCACHE; without them go
# reports the write miss as the misleading "package X is not in std".
# GOCACHE differs by OS; GOMODCACHE defaults to `~/go/pkg/mod`, while `~/go`
# itself stays read-only as a toolchain_read root.
"Library/Caches/go-build", # GOCACHE, macOS default
".cache/go-build", # GOCACHE, Linux default
"go/pkg/mod", # GOMODCACHE default
# Harn's package cache needs write: an entry is claimed through a lock file
# under `locks/` before it is read. `HARN_CACHE_DIR` overrides it, and the
# workspace env hands the child the resolved root so the two agree.
"Library/Caches/harn", # macOS default
".cache/harn", # Linux default
# Go env config (GOENV). `go` rewrites `go/env` on first use and fails with
# `writing go env config` when its parent is read-only. The Linux default
# `~/.config/go/env` sits under the read-only `.config/go` package-config
# root, so granting it needs a nested carve-out tracked separately.
"Library/Application Support/go", # GOENV, macOS default
# Cargo registry + git caches: crate sources, tarballs, the index, and git
# dependency checkouts. Build artifacts only; Cargo credentials and config
# live at the CARGO_HOME root, outside these, and stay read-only.
".cargo/registry", # crate cache/index/src
".cargo/git", # git dependency db + checkouts
".cargo/.package-cache", # Cargo's advisory build lock file
]