Repository navigation
Inspected REST endpoint: an encoded slash or conflicting framing headers cut the connection instead of returning a structured 403 #4671
Description
User Story
I use OpenShell to let an agent install the dependencies of real projects. When npm downloaded a dependency from GitLab, it got ECONNRESET and could not tell that the policy had blocked the request; the reason (%2F) was only in the supervisor's logs. When a request is blocked, I expect a 403 with the reason, as with other denials, so the agent can understand it.
Problem Statement
On an enforce REST endpoint, two request conditions make the supervisor close the TLS connection without any HTTP response (curl exit 56, unexpected eof while reading), instead of the structured 403 policy_denied JSON body it returns for an ordinary denied method or path:
- a request-target that contains an encoded slash (
%2F) on an endpoint withoutallow_encoded_slash; - a request that carries both
Transfer-EncodingandContent-Length.
In both cases the supervisor already knows why: it emits an OCSF NET:OPEN [MED] DENIED event with the exact reason. Only the client is left without it.
Impact / Why This Matters
An agent (or any client) cannot tell these policy decisions from a network fault, so it cannot report the reason or adjust its request; it typically retries. An ordinary denial names the policy and the rule in a JSON body, which an agent can read and act on. For the %2F case, the supervisor's own log even names the fix (set allow_encoded_slash: true on this endpoint), but the agent never sees it; the operator has to find it in openshell logs.
Related, but distinct: #3577 (an unlisted hostname terminates the boundary instead of a clean denial) and #3902 (%3B silently truncates the forwarded path).
Acceptance Criteria
- A request-target containing
%2Fon an endpoint withoutallow_encoded_slashgets an HTTP response (for example403with thepolicy_deniedbody and the reason) instead of a closed connection. - A request with both
Transfer-EncodingandContent-Lengthgets an HTTP error response (for example400) before the connection is closed. - Each response names the reason that the OCSF event already records.
Reproduction Steps
Uses only an OpenShell sandbox and the curl in its image; no third-party installs. Any image with curl and bash works.
-
Save
policy.yaml:version: 1 filesystem_policy: include_workdir: true read_only: [/usr, /lib, /etc] read_write: [/tmp, /dev/null] landlock: compatibility: hard_requirement process: run_as_user: "1000" run_as_group: "1000" network_policies: github: endpoints: - host: api.github.com port: 443 protocol: rest enforcement: enforce rules: - allow: method: GET path: "/**" - allow: method: POST path: /markdown binaries: - path: /usr/bin/curl
-
openshell sandbox create --name a2 --from <image-with-curl> --policy policy.yaml -
In the sandbox:
u=https://api.github.com # control: an ordinary denial returns a structured 403 curl -sS -o /dev/null -w '%{http_code}\n' -X POST -H 'Content-Type: application/json' --data '{"text":"hi"}' $u/repos/NVIDIA/OpenShell/issues # (a) encoded slash curl -sS -o /dev/null -w '%{http_code}\n' $u/repos/NVIDIA%2FOpenShell # (d) both framing headers curl -sS -o /dev/null -w '%{http_code}\n' -X POST -H 'Content-Type: application/json' -H 'Transfer-Encoding: chunked' -H 'Content-Length: 16' --data '{"text":"hello"}' $u/markdown
→ control:
403, body{"error":"policy_denied","policy":"github","rule":"POST /repos/NVIDIA/OpenShell/issues",…}.
→ (a) and (d):000, curl exit 56,OpenSSL SSL_read: … unexpected eof while reading. -
openshell logs a2shows aDENIEDevent with the reason for each cut connection (see Logs).
Suggested UX (if applicable)
No response
Environment
- OpenShell: v0.1.4 (gateway, supervisor and sandbox images 0.1.4; also seen on v0.1.3)
- OS: macOS 26.6.2 (Darwin 25.6.0)
- Deployment: local gateway, Docker driver; Docker 29.5.2 via Colima 0.10.3
Logs
HTTP:POST [MED] DENIED POST http://api.github.com:443/repos/NVIDIA/OpenShell/issues [policy:github engine:l7] [reason:L7_REQUEST deny POST api.github.com:443/repos/NVIDIA/OpenShell/issues reason=POST /repos/NVIDIA/OpenShell/issues not permitted by policy]
NET:OPEN [MED] DENIED api.github.com:443 [policy:github engine:l7] [reason:HTTP request-target rejected: request-target contains an encoded '/' (%2F) which is not allowed on this endpoint; set allow_encoded_slash: true on this endpoint if the upstream requires encoded slashes]
NET:OPEN [MED] DENIED api.github.com:443 [policy:github engine:l7] [reason:Request contains both Transfer-Encoding and Content-Length headers]
Activity