-
Notifications
You must be signed in to change notification settings - Fork 397
Description
Summary
The forward proxy path (handle_forward_proxy() in proxy.rs) does not perform L7 request inspection, even when the matched endpoint has protocol: rest with explicit rules or access presets configured. This means any endpoint with allowed_ips that is accessed via plain http:// silently bypasses L7 enforcement.
A policy author who writes:
endpoints:
- host: internal-svc.corp
port: 8080
allowed_ips: ["10.0.0.0/8"]
protocol: rest
enforcement: enforce
access: read-onlyExpects that POST/PUT/DELETE are blocked. They are — but only via HTTPS (CONNECT path). A curl http://internal-svc.corp:8080/data -X POST goes through the forward proxy path and succeeds, because forward proxy v1 relays the request without L7 evaluation.
Reproduction
- Start a sandbox with a policy that has a private IP endpoint with
protocol: rest+access: read-only+allowed_ips - From inside the sandbox:
curl -X GET http://<host>:<port>/data— succeeds (expected) - From inside the sandbox:
curl -X POST http://<host>:<port>/data -d "test"— also succeeds (unexpected — should be blocked by L7 read-only) - Compare with HTTPS:
curl -X POST https://<host>:<port>/data -d "test"— blocked by L7 (correct, goes through CONNECT path)
Root Cause
security-policy.md line 719 documents this as a V1 simplification:
V1 simplifications: Forward proxy v1 injects
Connection: close(no keep-alive) and does not perform L7 inspection on the forwarded traffic.
The forward proxy path in proxy.rs (handle_forward_proxy()) performs OPA L4 evaluation (step 3) and SSRF checks (steps 4-5), but after connecting upstream it rewrites and relays the request without calling evaluate_l7_request() or checking the endpoint's protocol/rules/access fields.
Impact
Any endpoint with allowed_ips that a sandbox process accesses via plain HTTP has no L7 enforcement, regardless of what the policy specifies. The policy appears to enforce method/path restrictions, but they are silently skipped.
This affects the most security-sensitive use case — internal/private services are typically the endpoints that need L7 enforcement most (databases, admin APIs, internal tools).
Proposed Fix
The forward proxy path already parses the HTTP request (step 7 — URL rewriting). Insert L7 evaluation between steps 6 (connect upstream) and 7 (rewrite + forward):
- After OPA L4 allows and upstream connection is established, call
query_l7_config()for the matched endpoint - If the endpoint has
protocolconfigured, evaluate the request method and path against the L7 rules - If L7 denies, return 403 to the client (same as CONNECT L7 deny)
- If L7 allows or no L7 config, proceed with the existing relay
This reuses the existing L7 evaluation infrastructure from the CONNECT path.
Workaround
Until fixed, policy authors should be aware that allowed_ips endpoints accessed via plain HTTP are effectively L4-only regardless of protocol/rules/access settings. To enforce L7 on internal services, ensure clients use HTTPS (which routes through the CONNECT path where L7 is enforced).
Context
Found during development of OpenShell Policy Prover (OPP), a formal verification tool for sandbox policies. OPP's cross-layer reasoning flagged the L4-only endpoint as a write bypass, and live testing in a sandbox confirmed that the forward proxy path skips L7 even when configured.
The original forward proxy feature issue (#155) listed "Integration test with L7 inspection" as a test consideration, suggesting L7 was intended but deferred.