Repository navigation
Proxy-mode baseline enrichment overrides include_workdir: false — workdir added to read_write unconditionally #905
Description
Summary
When a sandbox policy sets include_workdir: false and places the workdir (e.g. /sandbox) in read_only, the proxy-mode baseline enrichment in enrich_proto_baseline_paths() unconditionally adds /sandbox to read_write, defeating the policy's read-only intent.
Landlock grants the union of matching rules, so /sandbox appearing in both read_only and read_write results in full write access — the opposite of what the policy requested.
Related
- fix(sandbox): two-phase Landlock to fix privilege ordering and add enforcement tests #810 — the two-phase prepare/enforce PR that landed in 0.0.29.
prepare()correctly respectsinclude_workdir: false, but the enrichment runs beforeprepare()and doesn't check the flag. - [All Platform][Security]OpenShell 0.0.26 does not enforce Landlock filesystem policy — /sandbox writable on all platforms NemoClaw#1739 — downstream issue tracking Landlock enforcement
- fix(install): bump OpenShell max version to 0.0.29 for Landlock enforcement NemoClaw#2141 — downstream PR bumping to OpenShell 0.0.29
Root Cause
The hardcoded proxy baseline in enrich_proto_baseline_paths():
PROXY_BASELINE_READ_WRITE: ["/sandbox", "/tmp"]
This adds /sandbox to read_write if it's not already in the read_write list. It does not check:
- Whether
include_workdirisfalse - Whether the path is already in
read_only(indicating deliberate read-only intent)
Flow
- Gateway delivers policy:
/sandboxinread_only,include_workdir: false,rw: 4paths enrich_proto_baseline_paths()adds/sandboxtoread_write→rw: 5(logged asCONFIG:ENRICHED)prepare()checksinclude_workdir— it'sfalse, so it doesn't add workdir again (but it's already there from step 2)- Ruleset built with
/sandboxin bothread_onlyandread_write→ Landlock union =read_write restrict_self()enforces — Landlock is active but/sandboxis writable
Evidence from Testing (OpenShell 0.0.29, NemoClaw sandbox)
Landlock IS enforced (confirming #810 fix works):
$ touch /dev/shm/test → Permission denied (DAC 1777, not in any policy list)
$ touch /var/tmp/test → Permission denied (DAC 1777, not in any policy list)
But workdir is writable despite read_only policy intent:
$ touch /sandbox/test → OK (should be blocked)
$ touch /sandbox/.openclaw/test → OK (should be blocked)
$ touch /sandbox/.local/test → OK (should be blocked)
Policy delivered by gateway (correct):
include_workdir: false
read_only: [/sandbox, /sandbox/.openclaw, ...]
read_write: [/tmp, /dev/null, /sandbox/.openclaw-data, /sandbox/.nemoclaw] # 4 paths
Policy after enrichment (incorrect):
CONFIG:ENRICHED — ro:9 rw:5 (one path added to rw)
Startup log confirms no fallback to container-disk policy:
2026-04-21T16:59:25.188Z INFO openshell_sandbox: Fetching sandbox policy via gRPC
2026-04-21T16:59:25.210Z INFO openshell_sandbox: CONFIG:ENRICHED ...
2026-04-21T16:59:25.212Z INFO openshell_sandbox: CONFIG:PROBED ro:9 rw:5
Suggested Fix
In enrich_proto_baseline_paths(), before adding a baseline path to read_write:
- Check if
include_workdirisfalseand the path matches the workdir — if so, skip it - Or: check if the path already exists in
read_only— if so, respect the explicit read-only intent and don't promote it
Option 2 is more general and handles cases beyond just the workdir.
Environment
- OpenShell: 0.0.29
- Kernel: Linux 6.8.0-1053-gcp (Landlock ABI v4)
- NemoClaw: alpha (prekshi/openshell-0.0.29-landlock branch)
Activity
johntmyers commentedon Apr 21, 2026
Implementation Plan
Issue type:
fixComplexity: Low
Confidence: High — clear path
Summary
The regression is in proxy-mode baseline filesystem enrichment inside
crates/openshell-sandbox/src/lib.rs. The fix should preserve explicitread_onlyintent when a baseline read-write path like/sandboxis already present inread_only, so proxy enrichment no longer promotes that path to writable access in either the proto or local-policy code paths.Scope
crates/openshell-sandbox/src/lib.rs: update proxy baseline enrichment so explicitread_onlyentries take precedence over baselineread_writeadditions, and keep the proto and localSandboxPolicyenrichment flows consistent.crates/openshell-sandbox/src/lib.rstests: add regression coverage for policies that setinclude_workdir: falseand explicitly place/sandboxinread_only, ensuring enrichment does not add it toread_write.architecture/sandbox.mdandarchitecture/security-policy.md: document that baseline enrichment skips system-injectedread_writepromotions when the same path is explicitly configured asread_only.Implementation Steps
read_writepath is skipped when that path already exists inread_only, preserving explicit operator intent.enrich_proto_baseline_paths()andenrich_sandbox_baseline_paths()so gRPC-delivered and local-file policies behave the same way./sandboxregression and the general "explicit read-only beats baseline read-write" behavior.Test Plan
crates/openshell-sandbox/src/lib.rstests to verify enrichment leaves/sandboxread-only when it is explicitly configured there, and that no overlappingread_only/read_writeentry is introduced by enrichment.e2e/changes are expected for this fix.Risks & Open Questions
SandboxPolicyenrichment path inconsistent. The implementation should keep both helpers aligned./tmpshould remain baseline writable unless a policy explicitly marks it read-only; the change should not reduce baseline access more broadly than intended.Documentation Impact
architecture/sandbox.mdandarchitecture/security-policy.mdto reflect that explicitread_onlypolicy entries override system-injected baselineread_writeenrichment.Revision 1 — initial plan
johntmyers commentedon Apr 21, 2026
Implementation Complete
PR: #910
What was built
Proxy-mode baseline enrichment now preserves explicit
read_onlyfilesystem intent instead of promoting the same path intoread_write. The fix covers both proto-backed and local-file policy enrichment and adds regression tests for each code path.Tests
Docs updated
architecture/sandbox.mdarchitecture/security-policy.mdThe issue will auto-close when the PR is merged.
fix(install): bump OpenShell max version to 0.0.29 for Landlock enfor…
fix(sandbox): preserve explicit read-only baseline paths (#910)