Repository navigation
bug(cli): policy update --add-endpoint rejects allow_encoded_slash, the same option its denial message tells users to set #4926
Description
User Story
I use OpenShell to run npm install inside sandboxes. Scoped packages make the registry request-target contain %2F (/registry.npmjs.org/@types%2Fnode), and OpenShell's L7 parser rejects that target unless the endpoint sets allow_encoded_slash: true.
I directly encountered that this option can only be set by pushing a whole policy document. The incremental openshell policy update --add-endpoint path rejects it — and the rejection text is the same message that tells users to configure the option in the first place.
Problem Statement
With an endpoint allowed but without the option, a scoped install fails closed with:
NET:OPEN [MED] DENIED registry.npmjs.org:443 [policy:dev_registries engine:http-parser]
[reason:HTTP request-target rejected: request-target contains an encoded '/' (%2F)
which is not allowed on this endpoint; passthrough credential relay uses strict path
parsing, so configure this endpoint with protocol: rest and allow_encoded_slash: true]
Following that advice from the CLI fails:
$ openshell policy update <sandbox> --rule-name enc_test --binary /usr/bin/curl \
--add-endpoint "registry.npmjs.org:443:full:rest:enforce:allow_encoded_slash=true" --dry-run
Error: --add-endpoint options segment supports only 'allow-uninspected-credentials',
'websocket-credential-rewrite', 'request-body-credential-rewrite', and
'allowed-ip=<CIDR-or-IP>'; got 'allow_encoded_slash=true' in
'registry.npmjs.org:443:full:rest:enforce:allow_encoded_slash=true'The identical endpoint without the option passes validation (--dry-run renders the merged policy), so the field itself is the only difference.
The same rule defined inside a full policy document and applied with openshell policy set works: scoped installs succeed afterwards and the audit shows the encoded target as allowed:
HTTP:GET [INFO] ALLOWED GET https://registry.npmjs.org/@types%2Fnode
Impact / Why This Matters
- The documented remediation for
%2Ftargets is unreachable through the incremental CLI, which is the natural tool for changing one rule on a live sandbox. Operators must replace the entire policy document to grant a single encoded-path permission, i.e. a much larger change surface than adding a rule. - The error message contradicts itself: it directs the user to set an option that the same subcommand refuses.
- Scoped npm and GitLab-style (
group%2Fproject) dependencies cannot be enabled incrementally at all, so any automated "approve the denial, retry" workflow is blocked for this class of target and requires a manual full-policy push instead.
Acceptance Criteria
-
openshell policy update --add-endpointaccepts the encoded-slash option (whatever spelling is chosen, e.g.allow-encoded-slash/allow_encoded_slash=true), and--dry-runprints the field in the merged endpoint. - After applying that update to a live sandbox, a request-target containing
%2Fis allowed at the L7 layer and audit showsHTTP:* ALLOWEDrather than anengine:http-parserdenial. - The "supported options" error either lists the field or names a working alternative command for setting it.
Reproduction Steps
openshell sandbox create --name enc -- sh -c 'sleep 900'(default policy).- Inside the sandbox:
npm install @types/node→ fails with the%2Fdenial above. - On the host: run the
policy update --add-endpoint ...:allow_encoded_slash=true --dry-runcommand → rejected by the options whitelist. - Same endpoint without the option →
--dry-runsucceeds. - Create a full policy YAML with the endpoint set to
protocol: rest,access: full,allow_encoded_slash: true, apply withopenshell policy set, then repeat step 2 → install succeeds.
Suggested UX
Extend the --add-endpoint options whitelist with the encoded-slash flag (matching the schema field name), or allow --add-endpoint to take a YAML/JSON endpoint object so every schema field is expressible incrementally:
$ openshell policy update sb1 --rule-name npm --binary /usr/local/node/bin/node \
--add-endpoint "registry.npmjs.org:443:full:rest:enforce:allow-encoded-slash" --waitEnvironment
- OpenShell 0.1.5 (CLI, gateway, supervisor, sandbox runtime all 0.1.5)
- Gateway: local, mTLS, Docker compute driver 29.9.2 (cgroup v2), single host
- Host OS: Windows 10 22H2 (19045.3803) with WSL 2.9.13, Ubuntu 24.04, kernel 6.18.40.1-microsoft-standard-WSL2
- Sandbox image: Ubuntu 24.04 based, Node.js 22.14.0 (npm 10.9.2)
- Related: The prover answers
unsupportedfor any policy that setsallow_encoded_slash#4672 (prover returnsunsupportedfor policies that setallow_encoded_slash), Inspected REST endpoint: an encoded slash or conflicting framing headers cut the connection instead of returning a structured 403 #4671 (encoded slash cuts the connection instead of returning 403)
Activity
youyouhe commentedon Oct 26, 2026
Additional evidence and environment
Environment
gateway info→Status: healthy, compute driverdocker 0.1.5(protocol 1.0)cgroup=systemd/2, runtimeruncopenshell-dev-all:1.2(Ubuntu 24.04 + Node.js 22.14.0 / npm 10.9.2)ghcr.io/nvidia/openshell/sandbox:0.1.5,ghcr.io/nvidia/openshell/supervisor:0.1.5Full transcript
Step 1 — endpoint declared as
protocol: tcp(the shape an operator naturally writes first)Step 2 — scoped install fails; audit line (complete, untruncated in the source log before the trailing ellipsis):
Step 3 — the incremental CLI cannot express the fix its own message recommends:
Step 4 — control: identical endpoint minus the option passes validation and renders in
--dry-run:Step 5 — same rule delivered inside a full document is accepted:
Step 6 — installs now succeed, two different scoped packages:
Step 7 — audit shows exactly the previously rejected target allowed at the L7 engine:
Conclusion from the evidence
Runtime behaviour is correct once the field reaches the supervisor. The only blocker is the option whitelist in
policy update --add-endpoint: there is no supported incremental way to set a schema field that the denial message instructs the user to set.