Skip to content

The prover answers unsupported for any policy that sets allow_encoded_slash #4672

Open

Description

@Kevinbeltran123

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_boundary with a counterexample.
  • The documentation says how a rule path with %2F is 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.

  1. 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
  2. openshell-prover check flag.yaml --boundary flag.yaml (the policy against itself) → unsupported, uses authority outside the initial model.

  3. Remove the allow_encoded_slash: true line and run the same command → within_boundary. With the rule path decoded (group/project), with or without the line: the same two results.

  4. Gateway constraint: add a second policy on gitlab.com:443 without the option (for example access: read-only for /usr/bin/git). openshell sandbox create --policy and openshell policy set both refuse it (see Logs). With the option on both endpoints, the sandbox is created.

  5. In that sandbox, curl https://gitlab.com/api/v4/projects/group%2Fproject/repository/archive.tar.gz passes the rule (GitLab's own 404 Project Not Found), and the decoded path …/projects/group/project/… gets 403 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-prover 0.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]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions