Repository navigation
The prover answers unsupported for any policy that sets allow_encoded_slash #4672
Description
User Story
In a personal project, I use OpenShell to let an agent install npm dependencies. Scoped packages arrive as @scope%2fname and GitLab dependencies as group%2Fproject, so the policy needs allow_encoded_slash. When I checked it with openshell-prover, it answered unsupported for the whole policy, not just those rules. I ended up approving that policy by hand, without a proof, and blocking GitLab dependencies entirely.
Problem Statement
openshell-prover check returns unsupported (reason_code: unsupported_policy_shape, boundary policy rule '…' uses authority outside the initial model) for any candidate or boundary that sets allow_encoded_slash: true on an endpoint, whatever its rules. The same file without that line returns within_boundary.
The supervisor needs the option to forward a request-target that contains %2F (without it the connection is cut, #4671), and with it a rule path matches with %2F as written, not decoded. The prover documentation lists the REST shapes it reports as unsupported (audit mode, a host and port with REST and non-REST endpoints, query rules, ? or brackets in paths, other protocols); this option is not among them.
Related but distinct: #4277 reports unsupported for some REST rule lists (uses an unsupported REST allow rule, still on 0.1.4 for its repro). Here the rules alone prove fine; adding allow_encoded_slash is what makes the check unsupported, with a different reason.
Impact / Why This Matters
openshell-prover check returns unsupported (reason_code: unsupported_policy_shape, boundary policy rule '…' uses authority outside the initial model) for any candidate or boundary that sets allow_encoded_slash: true on an endpoint, whatever its rules. The same file without that line returns within_boundary.
The supervisor needs the option to forward a request-target that contains %2F (without it the connection is cut, #4671), and with it a rule path matches with %2F as written, not decoded. The prover documentation lists the REST shapes it reports as unsupported (audit mode, a host and port with REST and non-REST endpoints, query rules, ? or brackets in paths, other protocols); this option is not among them.
Related but distinct: #4277 reports unsupported for some REST rule lists (uses an unsupported REST allow rule, still on 0.1.4 for its repro). Here the rules alone prove fine; adding allow_encoded_slash is what makes the check unsupported, with a different reason.
Acceptance Criteria
- A candidate and a boundary that both set the option on the same endpoint, with the same encoded rule path, return
within_boundary. - A candidate that allows an encoded path the boundary does not, or sets the option where the boundary does not, returns
exceeds_boundarywith a counterexample. - The documentation says how a rule path with
%2Fis compared (as written, as the supervisor matches it).
Reproduction Steps
Uses only openshell-prover, an OpenShell sandbox and the curl in its image; no third-party installs.
-
Save
flag.yaml:version: 1 filesystem_policy: include_workdir: true read_only: [/usr, /lib, /etc] read_write: [/tmp] landlock: compatibility: hard_requirement process: run_as_user: "1000" run_as_group: "1000" network_policies: archive: endpoints: - host: gitlab.com port: 443 protocol: rest enforcement: enforce allow_encoded_slash: true rules: - allow: method: GET path: /api/v4/projects/group%2Fproject/repository/archive.tar.gz binaries: - path: /usr/bin/curl
-
openshell-prover check flag.yaml --boundary flag.yaml(the policy against itself) →unsupported,uses authority outside the initial model. -
Remove the
allow_encoded_slash: trueline and run the same command →within_boundary. With the rule path decoded (group/project), with or without the line: the same two results. -
Gateway constraint: add a second policy on
gitlab.com:443without the option (for exampleaccess: read-onlyfor/usr/bin/git).openshell sandbox create --policyandopenshell policy setboth refuse it (see Logs). With the option on both endpoints, the sandbox is created. -
In that sandbox,
curl https://gitlab.com/api/v4/projects/group%2Fproject/repository/archive.tar.gzpasses the rule (GitLab's own404 Project Not Found), and the decoded path…/projects/group/project/…gets403 policy_denied. So the supervisor matches the rule path as written, which the prover would need to model.
Suggested UX (if applicable)
No response
Environment
- OpenShell: v0.1.4 (gateway, supervisor, sandbox images and
openshell-prover0.1.4; also seen on v0.1.3) - Prover linked against Homebrew's z3 5.1.0
- OS: macOS 26.6.2 (Darwin 25.6.0)
- Deployment: local gateway, Docker driver; Docker 29.5.2 via Colima 0.10.3
Logs
$ openshell-prover check flag.yaml --boundary flag.yaml
result: unsupported
reason: boundary policy rule 'archive' uses authority outside the initial model
$ openshell sandbox create --policy conflict.yaml ...
network policies 'git' endpoint[0] (gitlab.com:443) and 'archive' endpoint[0] (gitlab.com:443) overlap on port(s) 443 with conflicting metadata: allow_encoded_slash=false vs true
HTTP:GET [INFO] ALLOWED GET http://gitlab.com:443/api/v4/projects/group%2Fproject/repository/archive.tar.gz [policy:archive engine:l7]
Activity