docs: Control UI identity + gateway pairing hardening + release verification

This commit is contained in:
Vincent Koc
2026-04-22 23:52:37 -07:00
parent ea3970f138
commit c8aec6b951
6 changed files with 83 additions and 0 deletions

View File

@@ -280,6 +280,21 @@ Recreate after changing any of these:
openclaw sandbox recreate --all
```
## Security hardening
OpenShell sandbox helpers that read remote workspace files use a pinned file
descriptor for the workspace root and walk ancestors from that pinned fd
instead of re-resolving the path for each read. Combined with an identity
recheck on every operation, this prevents a mid-turn symlink swap or a
hot-swapped workspace mount from redirecting reads outside the intended
remote workspace.
- Workspace root is opened once and pinned; later reads reuse that fd.
- Ancestor walks traverse relative entries from the pinned fd so they cannot
be redirected by a replacement directory higher in the path.
- The sandbox identity is rechecked before each read, so a recreated or
reassigned sandbox cannot silently serve files from a different workspace.
## Current limitations
- Sandbox browser is not supported on the OpenShell backend.

View File

@@ -117,6 +117,33 @@ The macOS app can optionally attempt a **silent approval** when:
If silent approval fails, it falls back to the normal “Approve/Reject” prompt.
## Metadata-upgrade auto-approval
When an already paired device reconnects with only non-sensitive metadata
changes (for example, display name or client platform hints), OpenClaw treats
that as a `metadata-upgrade` and auto-approves the reconnect without
prompting. Scope upgrades (read to write/admin) and public key changes are
**not** eligible for metadata-upgrade auto-approval — they stay as explicit
re-approval requests.
## QR pairing helpers
`/pair qr` renders the pairing payload as structured media so mobile and
browser clients can scan it directly. Device deletion now also sweeps stale
pending pairing requests for the same device id, so `nodes pending` no longer
shows orphaned rows after a revoke.
## Locality and forwarded headers
Gateway pairing treats a connection as loopback only when both the raw socket
and any upstream proxy evidence agree. If a request arrives on loopback but
carries `X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto` headers
that point at a non-local origin, that forwarded-header evidence disqualifies
the loopback locality claim. The pairing path then requires explicit approval
instead of silently treating the request as a same-host connect. See
[Trusted Proxy Auth](/gateway/trusted-proxy-auth) for the equivalent rule on
operator auth.
## Storage (local, private)
Pairing state is stored under the Gateway state directory (default `~/.openclaw`):

View File

@@ -941,6 +941,15 @@ Local device pairing:
trusted shared-secret helper flows.
- Tailnet and LAN connects, including same-host tailnet binds, are treated as
remote for pairing and still need approval.
- **Forwarded-header evidence disqualifies loopback locality.** If a request
arrives on loopback but carries `X-Forwarded-For` / `X-Forwarded-Host` /
`X-Forwarded-Proto` headers pointing at a non-local origin, the request is
treated as remote for pairing, trusted-proxy auth, and Control UI device
identity gating — it no longer qualifies for loopback auto-approval.
- **Metadata-upgrade auto-approval** applies only to non-sensitive reconnect
deltas on already paired devices (display name, client platform hints).
Scope upgrades (read to write/admin) and public key changes still require
explicit re-approval and are never silently upgraded.
Auth modes:

View File

@@ -82,6 +82,7 @@ Important runtime rule:
- Same-host loopback reverse proxies do **not** satisfy trusted-proxy auth.
- For same-host loopback proxy setups, use token/password auth instead, or route through a non-loopback trusted proxy address that OpenClaw can verify.
- Non-loopback Control UI deployments still need explicit `gateway.controlUi.allowedOrigins`.
- **Forwarded-header evidence overrides loopback locality.** If a request arrives on loopback but carries `X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto` headers pointing at a non-local origin, that evidence disqualifies the loopback locality claim. The request is treated as remote for pairing, trusted-proxy auth, and Control UI device-identity gating. This prevents a same-host loopback proxy from laundering forwarded-header identity into trusted-proxy auth.
### Configuration Reference

View File

@@ -112,6 +112,11 @@ OpenClaw has three public release lanes:
- npm release preflight fails closed unless the tarball includes both
`dist/control-ui/index.html` and a non-empty `dist/control-ui/assets/` payload
so we do not ship an empty browser dashboard again
- Post-publish verification also checks that the published registry install
contains non-empty bundled plugin runtime deps under the root `dist/*`
layout. A release that ships with missing or empty bundled plugin
dependency payloads fails the postpublish verifier and cannot be promoted
to `latest`.
- `pnpm test:install:smoke` also enforces the npm pack `unpackedSize` budget on
the candidate update tarball, so installer e2e catches accidental pack bloat
before the release publish path

View File

@@ -76,6 +76,31 @@ you revoke it with `openclaw devices revoke --device <id> --role <role>`. See
- Each browser profile generates a unique device ID, so switching browsers or
clearing browser data will require re-pairing.
## Personal identity (browser-local)
The Control UI supports a per-browser personal identity — a display name and
avatar that are attached to outgoing messages for attribution in shared
sessions. This identity lives in browser storage, is scoped to the current
browser profile, and does not leave the gateway host unless you explicitly
submit it with a request.
- Identity is **browser-local only**. It is not synced to other devices and is
not part of the gateway config file.
- Clearing site data or switching browsers resets the identity to empty; the
Control UI does not try to reconstruct one from server state.
- Nothing about the personal identity is persisted server-side beyond the
normal transcript authorship metadata on messages you actually send.
## Runtime config endpoint
The Control UI fetches its runtime settings from
`/__openclaw/control-ui-config.json`. That endpoint is gated by the same
gateway auth as the rest of the HTTP surface: unauthenticated browsers cannot
fetch it, and a successful fetch requires either an already valid gateway
token/password, Tailscale Serve identity, or a trusted-proxy identity. This
keeps Control UI feature flags and endpoint metadata from leaking to
unauthenticated scanners on shared hosts.
## Language support
The Control UI can localize itself on first load based on your browser locale.
@@ -109,6 +134,7 @@ locale picker lives in the Gateway Access card, not under Appearance.
plus plugin + channel schemas when available); Raw JSON editor is
available only when the snapshot has a safe raw round-trip
- If a snapshot cannot safely round-trip raw text, Control UI forces Form mode and disables Raw mode for that snapshot
- Raw JSON editor "Reset to saved" preserves the raw-authored shape (formatting, comments, `$include` layout) instead of re-rendering a flattened snapshot, so external edits survive a reset when the snapshot can safely round-trip
- Structured SecretRef object values are rendered read-only in form text inputs to prevent accidental object-to-string corruption
- Debug: status/health/models snapshots + event log + manual RPC calls (`status`, `health`, `models.list`)
- Logs: live tail of gateway file logs with filter/export (`logs.tail`)