docs(security): clarify node pairing trust boundary

This commit is contained in:
Peter Steinberger
2026-04-01 18:26:33 +09:00
parent 29784af1e2
commit 8b2d24b62b
4 changed files with 25 additions and 14 deletions

View File

@@ -66,17 +66,20 @@ Notes:
- `node.pair.request` is idempotent per node: repeated calls return the same
pending request.
- Repeated requests for the same pending node also refresh the stored node
metadata and allowlisted command set, so reconnect-driven repair flows do not
stay stuck on stale pending data.
metadata and the latest allowlisted declared command snapshot for operator visibility.
- Approval **always** generates a fresh token; no token is ever returned from
`node.pair.request`.
- Requests may include `silent: true` as a hint for auto-approval flows.
If a node is already paired but reconnects while declaring allowlisted commands
that are missing from its approved node record, the gateway creates a repair
pairing request. The current connection stays fail-closed on the previously
approved command set until that repair request is approved and the node
reconnects again.
Important:
- Node pairing is a trust/identity flow plus token issuance.
- It does **not** pin the live node command surface per node.
- Live node commands come from what the node declares on connect after the
gateway's global node command policy (`gateway.nodes.allowCommands` /
`denyCommands`) is applied.
- Per-node `system.run` allow/ask policy lives on the node in
`exec.approvals.node.*`, not in the pairing record.
## Auto-approval (macOS app)

View File

@@ -116,6 +116,7 @@ These patterns are commonly reported and are usually closed as no-action unless
- Claims that classify normal operator read-path access (for example `sessions.list`/`sessions.preview`/`chat.history`) as IDOR in a shared-gateway setup.
- Localhost-only deployment findings (for example HSTS on loopback-only gateway).
- Discord inbound webhook signature findings for inbound paths that do not exist in this repo.
- Reports that treat node pairing metadata as a hidden second per-command approval layer for `system.run`, when the real execution boundary is still the gateway's global node command policy plus the node's own exec approvals.
- "Missing per-user authorization" findings that treat `sessionKey` as an auth token.
## Researcher preflight checklist
@@ -370,10 +371,18 @@ stronger isolation between agents, run them under separate OS users or separate
If a macOS node is paired, the Gateway can invoke `system.run` on that node. This is **remote code execution** on the Mac:
- Requires node pairing (approval + token).
- Gateway node pairing is not a per-command approval surface. It establishes node identity/trust and token issuance.
- The Gateway applies a coarse global node command policy via `gateway.nodes.allowCommands` / `denyCommands`.
- Controlled on the Mac via **Settings → Exec approvals** (security + ask + allowlist).
- The per-node `system.run` policy is the node's own exec approvals file (`exec.approvals.node.*`), which can be stricter or looser than the gateway's global command-ID policy.
- Approval mode binds exact request context and, when possible, one concrete local script/file operand. If OpenClaw cannot identify exactly one direct local file for an interpreter/runtime command, approval-backed execution is denied rather than promising full semantic coverage.
- If you dont want remote execution, set security to **deny** and remove node pairing for that Mac.
This distinction matters for triage:
- A reconnecting paired node advertising a different command list is not, by itself, a vulnerability if the Gateway global policy and the node's local exec approvals still enforce the actual execution boundary.
- Reports that treat node pairing metadata as a second hidden per-command approval layer are usually policy/UX confusion, not a security boundary bypass.
## Dynamic skills (watcher / remote nodes)
OpenClaw can refresh the skills list mid-session:

View File

@@ -62,7 +62,8 @@ If you see `NODE_BACKGROUND_UNAVAILABLE`, bring the node app to the foreground a
These are different gates:
1. **Device pairing**: can this node connect to the gateway?
2. **Exec approvals**: can this node run a specific shell command?
2. **Gateway node command policy**: is the RPC command ID allowed by `gateway.nodes.allowCommands` / `denyCommands` and platform defaults?
3. **Exec approvals**: can this node run a specific shell command locally?
Quick checks:
@@ -74,12 +75,10 @@ openclaw approvals allowlist add --node <idOrNameOrIp> "/usr/bin/uname"
```
If pairing is missing, approve the node device first.
If pairing is fine but `system.run` fails, fix exec approvals/allowlist.
If `nodes describe` is missing a command, check the gateway node command policy and whether the node actually declared that command on connect.
If pairing is fine but `system.run` fails, fix exec approvals/allowlist on that node.
If `nodes describe` shows the node connected but the expected command is missing,
the approved node-pair record may be stale. In that case, reconnecting the node
should create a repair pairing request; approve it, then reconnect once more so
the gateway can expose the refreshed command set.
Node pairing is an identity/trust gate, not a per-command approval surface. For `system.run`, the per-node policy lives in that node's exec approvals file (`openclaw approvals get --node ...`), not in the gateway pairing record.
## Common node error codes