From 6636ca87f47fb1822f491d315380c8ed9988fa9e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 17 Mar 2026 09:54:19 -0700 Subject: [PATCH] docs(hooks): clarify trust model and audit guidance --- docs/automation/webhook.md | 2 ++ docs/cli/security.md | 2 +- docs/gateway/security/index.md | 3 +++ src/config/schema.help.ts | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/automation/webhook.md b/docs/automation/webhook.md index b35ee9d4469..38676a8fdbe 100644 --- a/docs/automation/webhook.md +++ b/docs/automation/webhook.md @@ -38,6 +38,7 @@ Every request must include the hook token. Prefer headers: - `Authorization: Bearer ` (recommended) - `x-openclaw-token: ` - Query-string tokens are rejected (`?token=...` returns `400`). +- Treat `hooks.token` holders as full-trust callers for the hook ingress surface on that gateway. Hook payload content is still untrusted, but this is not a separate non-owner auth boundary. ## Endpoints @@ -205,6 +206,7 @@ curl -X POST http://127.0.0.1:18789/hooks/gmail \ - Keep hook endpoints behind loopback, tailnet, or trusted reverse proxy. - Use a dedicated hook token; do not reuse gateway auth tokens. +- Prefer a dedicated hook agent with strict `tools.profile` and sandboxing so hook ingress has a narrower blast radius. - Repeated auth failures are rate-limited per client address to slow brute-force attempts. - If you use multi-agent routing, set `hooks.allowedAgentIds` to limit explicit `agentId` selection. - Keep `hooks.allowRequestSessionKey=false` unless you require caller-selected sessions. diff --git a/docs/cli/security.md b/docs/cli/security.md index 76a7ae75976..28b65f3629b 100644 --- a/docs/cli/security.md +++ b/docs/cli/security.md @@ -30,7 +30,7 @@ This is for cooperative/shared inbox hardening. A single Gateway shared by mutua It also emits `security.trust_model.multi_user_heuristic` when config suggests likely shared-user ingress (for example open DM/group policy, configured group targets, or wildcard sender rules), and reminds you that OpenClaw is a personal-assistant trust model by default. For intentional shared-user setups, the audit guidance is to sandbox all sessions, keep filesystem access workspace-scoped, and keep personal/private identities or credentials off that runtime. It also warns when small models (`<=300B`) are used without sandboxing and with web/browser tools enabled. -For webhook ingress, it warns when `hooks.defaultSessionKey` is unset, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`. +For webhook ingress, it warns when `hooks.token` reuses the Gateway token, when `hooks.defaultSessionKey` is unset, when `hooks.allowedAgentIds` is unrestricted, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`. It also warns when sandbox Docker settings are configured while sandbox mode is off, when `gateway.nodes.denyCommands` uses ineffective pattern-like/unknown entries (exact node command-name matching only, not shell-text filtering), when `gateway.nodes.allowCommands` explicitly enables dangerous node commands, when global `tools.profile="minimal"` is overridden by agent tool profiles, when open groups expose runtime/filesystem tools without sandbox/workspace guards, and when installed extension plugin tools may be reachable under permissive tool policy. It also flags `gateway.allowRealIpFallback=true` (header-spoofing risk if proxies are misconfigured) and `discovery.mdns.mode="full"` (metadata leakage via mDNS TXT records). It also warns when sandbox browser uses Docker `bridge` network without `sandbox.browser.cdpSourceRange`. diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md index 8193eb5ca2c..5fbd26a826e 100644 --- a/docs/gateway/security/index.md +++ b/docs/gateway/security/index.md @@ -243,7 +243,10 @@ High-signal `checkId` values you will most likely see in real deployments (not e | `gateway.real_ip_fallback_enabled` | warn/critical | Trusting `X-Real-IP` fallback can enable source-IP spoofing via proxy misconfig | `gateway.allowRealIpFallback`, `gateway.trustedProxies` | no | | `discovery.mdns_full_mode` | warn/critical | mDNS full mode advertises `cliPath`/`sshPort` metadata on local network | `discovery.mdns.mode`, `gateway.bind` | no | | `config.insecure_or_dangerous_flags` | warn | Any insecure/dangerous debug flags enabled | multiple keys (see finding detail) | no | +| `hooks.token_reuse_gateway_token` | critical | Hook ingress token also unlocks Gateway auth | `hooks.token`, `gateway.auth.token` | no | | `hooks.token_too_short` | warn | Easier brute force on hook ingress | `hooks.token` | no | +| `hooks.default_session_key_unset` | warn | Hook agent runs fan out into generated per-request sessions | `hooks.defaultSessionKey` | no | +| `hooks.allowed_agent_ids_unrestricted` | warn/critical | Authenticated hook callers may route to any configured agent | `hooks.allowedAgentIds` | no | | `hooks.request_session_key_enabled` | warn/critical | External caller can choose sessionKey | `hooks.allowRequestSessionKey` | no | | `hooks.request_session_key_prefixes_missing` | warn/critical | No bound on external session key shapes | `hooks.allowedSessionKeyPrefixes` | no | | `logging.redact_off` | warn | Sensitive values leak to logs/status | `logging.redactSensitive` | yes | diff --git a/src/config/schema.help.ts b/src/config/schema.help.ts index 82c07b176fb..4518d393ed2 100644 --- a/src/config/schema.help.ts +++ b/src/config/schema.help.ts @@ -1245,7 +1245,7 @@ export const FIELD_HELP: Record = { "hooks.path": "HTTP path used by the hooks endpoint (for example `/hooks`) on the gateway control server. Use a non-guessable path and combine it with token validation for defense in depth.", "hooks.token": - "Shared bearer token checked by hooks ingress for request authentication before mappings run. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.", + "Shared bearer token checked by hooks ingress for request authentication before mappings run. Treat holders as full-trust callers for the hook ingress surface, not as a separate non-owner role. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.", "hooks.defaultSessionKey": "Fallback session key used for hook deliveries when a request does not provide one through allowed channels. Use a stable but scoped key to avoid mixing unrelated automation conversations.", "hooks.allowRequestSessionKey": @@ -1253,7 +1253,7 @@ export const FIELD_HELP: Record = { "hooks.allowedSessionKeyPrefixes": "Allowlist of accepted session-key prefixes for inbound hook requests when caller-provided keys are enabled. Use narrow prefixes to prevent arbitrary session-key injection.", "hooks.allowedAgentIds": - "Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents.", + "Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents and reduce blast radius if a hook token is exposed.", "hooks.maxBodyBytes": "Maximum accepted webhook payload size in bytes before the request is rejected. Keep this bounded to reduce abuse risk and protect memory usage under bursty integrations.", "hooks.presets":