You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: enforce deny_read, deny_exec, and config protection inside sandbox (#5)
Real-world security testing revealed that none of the sandbox policies were
actually enforced inside the namespace — deny_read, deny_exec, and config
protection all failed silently while the target command ran normally.
Root cause: buildMountOverrides() joined all mount commands with && — any
single mount failure cascaded to skip ALL subsequent security setup, but the
target command still executed (separated by ; from the last for-loop).
Fixes:
- Add mount --make-rprivate / at sandbox entry for bind mount compatibility
- Rewrite buildMountOverrides() with independent mounts (no cascading &&)
- Add buildExecDenyOverrides() for kernel-level deny_exec enforcement
- Add tilde expansion (~/) in resolvePatterns() for home-dir paths
- Protect ~/.aigate/ config dir: tmpfs on Linux, Seatbelt deny on macOS
- Add Seatbelt (deny process-exec) rules for deny_exec on macOS
- Quote all paths in mount commands for space safety
- Update default config with ~/ prefixes and subcommand examples
- Mark resource_limits as coming soon in docs
Copy file name to clipboardExpand all lines: docs/user/README.md
+15-8Lines changed: 15 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -166,20 +166,22 @@ deny_read:
166
166
- ".env.*"
167
167
- "secrets/"
168
168
- "credentials/"
169
-
- ".ssh/"
169
+
- "~/.ssh/"
170
170
- "*.pem"
171
171
- "*.key"
172
-
- ".aws/"
173
-
- ".gcloud/"
172
+
- "~/.aws/"
173
+
- "~/.gcloud/"
174
+
- "~/.kube/config"
175
+
- "~/.npmrc"
176
+
- "~/.pypirc"
174
177
deny_exec:
175
178
- "curl"
176
179
- "wget"
177
180
- "nc"
178
181
- "ssh"
179
182
- "scp"
180
183
- "kubectl delete"
181
-
- "kubectl create"
182
-
- "docker rm"
184
+
- "kubectl exec"
183
185
allow_net:
184
186
- "api.anthropic.com"
185
187
- "api.openai.com"
@@ -248,11 +250,16 @@ Restricts outbound connections to domains listed in `allow_net`:
248
250
249
251
### Command blocking
250
252
251
-
`deny_exec`rules are checked **before** entering the sandbox. If the command (or a subcommand like `kubectl delete`) is in the deny list, aigate refuses to launch it. This is an application-level check, not a kernel feature.
253
+
`deny_exec` rules are enforced at two layers for defense-in-depth:
252
254
253
-
### Resource limits
255
+
1. **Pre-sandbox check**: Before entering the sandbox, aigate checks the command (and subcommands like `kubectl delete`) against the deny list and refuses to launch blocked commands.
256
+
2. **Kernel-level enforcement inside the sandbox**:
257
+
- **Linux**: Full command blocks use `mount --bind` to overlay denied binaries with a deny script. Subcommand blocks use wrapper scripts that check arguments before forwarding to the original binary.
258
+
- **macOS**: Full command blocks use Seatbelt `(deny process-exec)` rules enforced by Sandbox.kext. Subcommand blocks rely on the pre-sandbox check.
254
259
255
-
cgroups v2 enforce memory, CPU, and PID limits (Linux only).
260
+
### Resource limits *(coming soon)*
261
+
262
+
Resource limits (`max_memory`, `max_cpu_percent`, `max_pids`) are defined in the config but **not yet enforced**. Enforcement via cgroups v2 controllers is planned for a future release.
0 commit comments