fix: enforce device token scope containment

This commit is contained in:
Peter Steinberger
2026-04-26 07:24:59 +01:00
parent 26e4eb8e40
commit 8bbb143ab8
9 changed files with 243 additions and 104 deletions

View File

@@ -83,6 +83,8 @@ That bootstrap token carries the built-in pairing bootstrap profile:
- bootstrap scope checks are role-prefixed, not one flat scope pool:
operator scope entries only satisfy operator requests, and non-operator roles
must still request scopes under their own role prefix
- later token rotation/revocation remains bounded by both the device's approved
role contract and the caller session's operator scopes
Treat the setup code like a password while it is valid.

View File

@@ -95,9 +95,9 @@ If you omit `--scope`, later reconnects with the stored rotated token reuse that
token's cached approved scopes. If you pass explicit `--scope` values, those
become the stored scope set for future cached-token reconnects.
Non-admin paired-device callers can rotate only their **own** device token.
Also, any explicit `--scope` values must stay within the caller session's own
operator scopes; rotation cannot mint a broader operator token than the caller
already has.
The target token scope set must stay within the caller session's own operator
scopes; rotation cannot mint or preserve a broader operator token than the
caller already has.
```
openclaw devices rotate --device <deviceId> --role operator --scope operator.read --scope operator.write
@@ -111,6 +111,8 @@ Revoke a device token for a specific role.
Non-admin paired-device callers can revoke only their **own** device token.
Revoking some other device's token requires `operator.admin`.
The target token scope set must also fit within the caller session's own
operator scopes; pairing-only callers cannot revoke admin/write operator tokens.
```
openclaw devices revoke --device <deviceId> --role node
@@ -135,12 +137,15 @@ Pass `--token` or `--password` explicitly. Missing explicit credentials is an er
- These commands require `operator.pairing` (or `operator.admin`) scope.
- `gateway.nodes.pairing.autoApproveCidrs` is an opt-in Gateway policy for
fresh node device pairing only; it does not change CLI approval authority.
- Token rotation stays inside the approved pairing role set and approved scope
baseline for that device. A stray cached token entry does not grant a new
rotate target.
- Token rotation and revocation stay inside the approved pairing role set and
approved scope baseline for that device. A stray cached token entry does not
grant a token-management target.
- For paired-device token sessions, cross-device management is admin-only:
`remove`, `rotate`, and `revoke` are self-only unless the caller has
`operator.admin`.
- Token mutation is also caller-scope contained: a pairing-only session cannot
rotate or revoke a token that currently carries `operator.admin` or
`operator.write`.
- `devices clear` is intentionally gated by `--yes`.
- If pairing scope is unavailable on local loopback (and no explicit `--url` is passed), list/approve can use a local pairing fallback.
- `devices approve` requires an explicit request ID before minting tokens; omitting `requestId` or passing `--latest` only previews the newest pending request.

View File

@@ -360,8 +360,8 @@ enumeration of `src/gateway/server-methods/*.ts`.
<Accordion title="Device pairing and device tokens">
- `device.pair.list` returns pending and approved paired devices.
- `device.pair.approve`, `device.pair.reject`, and `device.pair.remove` manage device-pairing records.
- `device.token.rotate` rotates a paired device token within its approved role and scope bounds.
- `device.token.revoke` revokes a paired device token.
- `device.token.rotate` rotates a paired device token within its approved role and caller scope bounds.
- `device.token.revoke` revokes a paired device token within its approved role and caller scope bounds.
</Accordion>
<Accordion title="Node pairing, invoke, and pending work">
@@ -549,15 +549,15 @@ rather than the pre-handshake defaults.
reused when the client is reusing the stored per-device token.
- Device tokens can be rotated/revoked via `device.token.rotate` and
`device.token.revoke` (requires `operator.pairing` scope).
- Token issuance/rotation stays bounded to the approved role set recorded in
that device's pairing entry; rotating a token cannot expand the device into a
role that pairing approval never granted.
- Token issuance, rotation, and revocation stay bounded to the approved role set
recorded in that device's pairing entry; token mutation cannot expand or
target a device role that pairing approval never granted.
- For paired-device token sessions, device management is self-scoped unless the
caller also has `operator.admin`: non-admin callers can remove/revoke/rotate
only their **own** device entry.
- `device.token.rotate` also checks the requested operator scope set against the
caller's current session scopes. Non-admin callers cannot rotate a token into
a broader operator scope set than they already hold.
- `device.token.rotate` and `device.token.revoke` also check the target operator
token scope set against the caller's current session scopes. Non-admin callers
cannot rotate or revoke a broader operator token than they already hold.
- Auth failures include `error.details.code` plus recovery hints:
- `error.details.canRetryWithDeviceToken` (boolean)
- `error.details.recommendedNextStep` (`retry_with_device_token`, `update_auth_configuration`, `update_auth_credentials`, `wait_then_retry`, `review_auth_configuration`)