fix: Allow explicit override over deny patterns (#177)

* fix: Allow explicit override over deny patterns

* test: Non-glob expansion for overrides is expected
This commit is contained in:
Abhisek Datta
2026-03-06 10:10:15 +05:30
committed by GitHub
parent 70db1b3078
commit 2bb5dd3778
3 changed files with 132 additions and 13 deletions
+21 -9
View File
@@ -5,6 +5,18 @@ PMG sandbox design goal is to protect against unknown supply chain attacks using
We do not want to re-invent sandbox and likely rely on OS native sandbox primitives. This is at the cost of developer experience,
where we have to work within the limitations of the sandbox implementations that we use.
## Security Model
- **Default deny**: All operations are blocked unless explicitly allowed by the policy. An empty policy grants no access.
- **Deny rules override allow rules**: When a path appears in both allow and deny lists, the deny rule wins. Deny rules are placed after allow rules in the generated sandbox profile to ensure this.
- **Credential and sensitive file protection**: The sandbox automatically blocks read and write access to credential files regardless of user configuration. Protected files include `.env`, `.env.*`, `.aws`, `.gcloud`, `.kube`, `.ssh`, `.gnupg`, and `.docker/config.json`. These mandatory deny patterns are injected at translation time and cannot be removed by policy configuration or runtime overrides.
- **Git hooks are always blocked**: Write access to `.git/hooks/` in both `$CWD` and `$HOME` is always denied to prevent arbitrary code execution via repository hooks.
- **Git config is blocked by default**: Write access to `.git/config` is denied unless `allow_git_config: true` is set in the policy. This prevents credential helper manipulation.
- **Runtime overrides remove only exact-match deny entries**: When `--sandbox-allow` adds a path to an allow list, only a literal string match in the corresponding deny list is removed. Glob and wildcard deny patterns (e.g., `/etc/**`) are never removed. Mandatory deny patterns (credentials, git hooks) cannot be overridden because they are re-injected at translation time.
- **Profile inheritance is single-level**: A profile can inherit from one built-in profile. Allow and deny lists are merged using union semantics. Boolean fields (`allow_pty`, `allow_git_config`) in the child override the parent.
- **Variable expansion is runtime-only**: Policy paths use `${HOME}`, `${CWD}`, and `${TMPDIR}` which are expanded when the sandbox is set up, not when the policy is defined.
- **Process-level isolation only**: The sandbox restricts the package manager process and its children. It does not enforce CPU, memory, or disk quotas. Network filtering is coarse-grained — host-level filtering is not enforced on either platform.
## Requirements
- Bubblewrap on Linux
@@ -33,7 +45,7 @@ See [Bubblewrap Installation](https://github.com/containers/bubblewrap#installat
## Usage
- Make sure sandbox is enabled in your `config.yml` file.
- Make sure sandbox profiles are configured for the package managers you want to sandbox.
- Make sure sandbox profiles are configured for the package managers you want to sandbox.
See [configuration](./config.md) and [config/config.template.yml](../config/config.template.yml) for the configuration schema.
Once sandbox is enabled, you can run package manager commands with sandbox protection.
@@ -80,7 +92,7 @@ pmg \
Supported types: `read`, `write`, `exec`, `net-connect`, `net-bind`.
Overrides are additive (append to allow lists), non-persistent (apply to current invocation only), and logged in the event log for auditing. They cannot bypass explicit deny rules in the profile or mandatory security protections (`.env`, `.ssh`, `.aws`, `.git/hooks`, etc.).
Overrides are non-persistent (apply to current invocation only) and logged in the event log for auditing. An override adds the path to the allow list and removes an exact match entry from the corresponding deny list. Glob deny patterns are never removed. Mandatory security protections (`.env`, `.ssh`, `.aws`, `.git/hooks`, etc.) cannot be bypassed by overrides.
<details>
<summary>Custom policy overrides using Policy Templates</summary>
@@ -174,7 +186,7 @@ coarse-grained fallback strategies when glob patterns match many files.
- **Large patterns** (> 100 matches): Parent directory is mounted (coarse-grained, scalable)
- **Threshold**: 100 paths per pattern triggers coarse-grained fallback
**Network filtering**: All-or-nothing network isolation (via `--unshare-net`). Host-specific
**Network filtering**: All-or-nothing network isolation (via `--unshare-net`). Host-specific
filtering is not enforced.
</details>
@@ -211,7 +223,7 @@ the policy model into their own native policy format. Rules for policy are:
Profile is a named reference to a policy. It is used to associate a policy with a package manager. PMG ships with a set of built-in profiles
that are used to enforce the policies for the package manager. See [sandbox/profiles](../sandbox/profiles) for the list of built-in profiles.
Custom profiles can be created by copying a built-in profile and modifying the rules to suit the needs.
Custom profiles can be created by copying a built-in profile and modifying the rules to suit the needs.
See [sandbox/profiles/README.md](../sandbox/profiles/README.md) for more details.
### Policy Template
@@ -251,10 +263,10 @@ Find the log tag in the debug log file and use it to investigate the sandbox pol
grep "PMG_SBX_" /tmp/pmg-debug.log
```
Use `log(1)` to filter the log file by the log tag or generic `PMG_SBX_` prefix.
Use `log(1)` to filter the log file by the log tag.
```bash
log show --last 5m --predicate 'message ENDSWITH "PMG_SBX_"' --style compact
log show --last 5m --predicate 'message ENDSWITH "PMG_SBX_${TAG}"' --style compact
```
### Linux
@@ -282,6 +294,6 @@ bwrap --verbose [arguments...] -- npm install express
## References
- https://github.com/anthropic-experimental/sandbox-runtime
- https://geminicli.com/docs/cli/sandbox/
- https://github.com/containers/bubblewrap
- <https://github.com/anthropic-experimental/sandbox-runtime>
- <https://geminicli.com/docs/cli/sandbox/>
- <https://github.com/containers/bubblewrap>