#8683: fix: Exec approval bypass via client-controlled flags in system.run
gateway
stale
Cluster:
Device Pairing and Gateway Fixes
## Fix Summary
`system.run` trusts client-supplied `approved`/`approvalDecision` values. Because `node.invoke` accepts arbitrary `params` and forwards them unmodified to the node host, any operator with `operator.write` can mark a request as approved and skip the exec-approval workflow and allowlist enforcement. On macOS, the same untrusted `approvalDecision` is forwarded to the exec host request.
## Issue Linkage
Fixes #8682
## Security Snapshot
- CVSS v3.1: 8.8 (High)
- CVSS v4.0: 8.7 (High)
## Implementation Details
### Files Changed
- `src/gateway/server-methods/nodes.ts` (+14/-2)
### Technical Analysis
`system.run` trusts client-supplied `approved`/`approvalDecision` values. Because `node.invoke` accepts arbitrary `params` and forwards them unmodified to the node host, any operator with `operator.write` can mark a request as approved and skip the exec-approval workflow and allowlist enforcement. On macOS, the same untrusted `approvalDecision` is forwarded to the exec host request.
## Validation Evidence
- Command: `system.run`
- Status: failed
## Risk and Compatibility
non-breaking; compatibility impact was not explicitly documented in the original PR body.
## AI-Assisted Disclosure
AI-assisted: Codex CLI
This fix was generated with AI assistance (Codex CLI).
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the `node.invoke` gateway handler to prevent exec-approval bypasses by sanitizing `system.run` parameters: unless the caller has an approval-capable scope, it strips client-supplied `approved` and `approvalDecision` fields before forwarding params to the node host.
The change fits into the gateway’s role as an authorization and policy enforcement layer before delegating execution to `context.nodeRegistry.invoke`, and specifically addresses the previously untrusted forwarding path for `system.run`.
<h3>Confidence Score: 3/5</h3>
- This PR is likely correct but relies on assumptions about the authoritativeness of `client.connect.scopes`.
- The fix is small and targeted and should stop the described bypass if scopes are server-derived and immutable for the operator session; however, if `client.connect.scopes` is missing for some legitimate callers or can be influenced by the client/session handshake, it could either break approvals or fail to close the bypass. CI is also reported failing, so additional validation is warranted.
- src/gateway/server-methods/nodes.ts (verify authn/authz invariants for `client.connect.scopes` in this handler)
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#21663: fix(gateway): prevent self-approval of timed-out exec requests
by AI-Reviewer-QS · 2026-02-20
81.4%
#20014: fix(nodes): use formatExecCommand for approval request command text
by openperf · 2026-02-18
76.6%
#12802: fix(gateway): default unscoped operator connections to read-only
by yubrew · 2026-02-09
76.1%
#20435: fix(exec): prioritize user 'always allow' config over tool defaults...
by ChisomUma · 2026-02-18
75.4%
#21661: fix(agents): treat approval timeout as denial regardless of askFall...
by AI-Reviewer-QS · 2026-02-20
75.0%
#9200: Fix: Strip dangerous env vars from baseEnv in host execution
by vishaltandale00 · 2026-02-05
74.9%
#23708: fix(gateway): auto-approve scope upgrades for loopback clients
by widingmarcus-cyber · 2026-02-22
74.3%
#21651: fix(gateway): token fallback + operator.admin scope superset in pai...
by lan17 · 2026-02-20
73.8%
#20089: fix(gateway): preserve control-ui scopes when dangerouslyDisableDev...
by vashkartik · 2026-02-18
73.2%
#17605: fix: preserve scopes when disableControlUiDeviceAuth is enabled
by MisterGuy420 · 2026-02-16
72.8%