openclaw - ✅(Solved) Fix [Bug]: Hook ingress token unlocks password-mode gateway auth [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#84337Fetched 2026-05-20 03:41:22
View on GitHub
Comments
1
Participants
2
Timeline
10
Reactions
1
Author
Timeline (top)
labeled ×8commented ×1cross-referenced ×1

Root Cause

The issue crosses a documented trust boundary because attacker-controlled input can trigger behavior that the protected component should reserve for authorized callers. This is exploitable vulnerability behavior rather than advisory hardening because the current implementation permits a concrete security property violation.

Fix Action

Fixed

PR fix notes

PR #84338: fix: Hook ingress token unlocks password-mode gateway auth

Description (problem / solution / changelog)

Summary

  • Problem: When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.
  • Why it matters: Add the missing security-audit coverage for password-mode reuse.
  • What changed: Add the missing security-audit coverage for password-mode reuse.
  • What did NOT change (scope boundary): No unrelated defaults, migrations, or compatibility behavior were intentionally changed.

Motivation

  • Add the missing security-audit coverage for password-mode reuse.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #84337
  • Related #
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.
  • Real environment tested: See Repro + Verification.
  • Exact steps or command run after this patch: node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check reported passed.
  • Observed result after fix: passed
  • What was not tested: Interactive/manual scenarios not captured in the staged issue bundle.
  • Before evidence (optional but encouraged): See the linked issue analysis.

Root Cause (if applicable)

  • Root cause: Add the missing security-audit coverage for password-mode reuse.
  • Missing detection / guardrail: No narrower detection note was recorded in the issue bundle.
  • Contributing context (if known): See the linked issue analysis and changed files below.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this: Validation command node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check
  • Target test or file: Not explicitly recorded in the issue bundle.
  • Scenario the test should lock in: When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.
  • Why this is the smallest reliable guardrail: It validates the failing behavior on the touched path without expanding scope.
  • Existing test that already covers this (if any): Unknown.
  • If no new test is added, why not: The staged bundle did not record a narrower regression target.

User-visible / Behavior Changes

  • None beyond resolving the linked issue's broken behavior.

Diagram (if applicable)

N/A

Security Impact (required)

  • New permissions/capabilities? (Yes/No): No
  • Secrets/tokens handling changed? (Yes/No): Yes
  • New/changed network calls? (Yes/No): Yes
  • Command/tool execution surface changed? (Yes/No): Yes
  • Data access scope changed? (Yes/No): No
  • If any Yes, explain risk + mitigation: Add the missing security-audit coverage for password-mode reuse.. Mitigation: node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check reported passed.

Repro + Verification

Environment

  • OS: N/A
  • Runtime/container: N/A
  • Model/provider: github-copilot/gpt-5.3-codex
  • Integration/channel (if any): N/A
  • Relevant config (redacted): AI-assisted=yes

Steps

  1. Reproduce the linked issue using the recorded issue bundle.
  2. Apply the fix from this branch.
  3. Run node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check.

Expected

  • When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.
  • Validation passes for the touched behavior.

Actual

  • Validation status: passed

Evidence

  • Validation evidence: node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check reported passed.
  • CVSS v3.1: 8.8 (High)
  • CVSS v4.0: 8.7 (High)
  • Changed files:
  • src/gateway/startup-auth.test.ts (+42/-3)
  • src/gateway/startup-auth.ts (+11/-5)
  • src/security/audit-extra.sync.ts (+17/-17)
  • src/security/audit-hooks-routing.test.ts (+29/-0)

Human Verification (required)

  • Verified scenarios: When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.
  • Edge cases checked: node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check completed with status passed.
  • What you did not verify: Interactive/manual scenarios not captured in the staged issue bundle.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No): Yes
  • Config/env changes? (Yes/No): No
  • Migration needed? (Yes/No): No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Regression in the touched behavior while closing the linked issue.
    • Mitigation: node scripts/run-oxlint.mjs 'src/security/audit-extra.sync.ts' 'src/security/audit-hooks-routing.test.ts' && node scripts/run-vitest.mjs 'src/security/audit-extra.sync.test.ts' 'src/security/audit-hooks-routing.test.ts' && pnpm build && pnpm check reported passed and the changed-file scope stayed limited to the recorded diff.

Changed files

  • src/gateway/startup-auth.test.ts (modified, +42/-3)
  • src/gateway/startup-auth.ts (modified, +11/-5)
  • src/security/audit-extra.sync.ts (modified, +17/-17)
  • src/security/audit-hooks-routing.test.ts (modified, +29/-0)

Code Example

const token = getBearerToken(params.req);
const authResult = await authorizeHttpGatewayConnect({
  auth: params.auth,
  connectAuth: token ? { token, password: token } : null,
});

if (auth.mode === "password") {
  return authorizePasswordAuth({
    authPassword: auth.password,
    connectPassword: connectAuth?.password,
  });
}

const gatewayToken =
  params.auth.mode === "token" ? (normalizeOptionalString(params.auth.token) ?? "") : "";
if (hooksToken !== gatewayToken) {
  return;
}
RAW_BUFFERClick to expand / collapse

Severity Assessment

CVSS Assessment

Metricv3.1v4.0
Score8.8 / 10.08.7 / 10.0
SeverityHighHigh
VectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CalculatorCVSS v3.1 CalculatorCVSS v4.0 Calculator

Threat Model Alignment

Classification: security-specific

The issue crosses a documented trust boundary because attacker-controlled input can trigger behavior that the protected component should reserve for authorized callers. This is exploitable vulnerability behavior rather than advisory hardening because the current implementation permits a concrete security property violation.

Impact

When hooks.token equals gateway.auth.password, any caller that only knows the hook ingress bearer can authenticate directly to password-mode Gateway HTTP surfaces. That bypasses hook-specific routing controls and upgrades a hook token into full operator access, including owner-only tool behavior on /tools/invoke.

Affected Component

File: src/gateway/http-auth-utils.ts:111, src/gateway/auth.ts:550, src/gateway/startup-auth.ts:224, src/security/audit-extra.sync.ts:516, src/security/audit-hooks-routing.test.ts

const token = getBearerToken(params.req);
const authResult = await authorizeHttpGatewayConnect({
  auth: params.auth,
  connectAuth: token ? { token, password: token } : null,
});

if (auth.mode === "password") {
  return authorizePasswordAuth({
    authPassword: auth.password,
    connectPassword: connectAuth?.password,
  });
}

const gatewayToken =
  params.auth.mode === "token" ? (normalizeOptionalString(params.auth.token) ?? "") : "";
if (hooksToken !== gatewayToken) {
  return;
}

Technical Reproduction

  1. Configure a gateway with hooks.enabled: true, gateway.auth.mode: "password", and the same secret value in hooks.token and gateway.auth.password.
  2. Start OpenClaw, then send a normal hook request such as POST /hooks/wake with Authorization: Bearer <shared-secret>; the hook ingress path accepts the credential via extractHookToken() and safeEqualSecret().
  3. Reuse the same Authorization: Bearer <shared-secret> header against POST /tools/invoke (or another shared-secret HTTP surface). checkGatewayHttpRequestAuth() forwards that bearer into both token and password, so password-mode auth succeeds and the caller is treated as a trusted operator.

Demonstrated Impact

src/gateway/server/hooks-request-handler.ts:204-223 authenticates hook callers with hooks.token, while src/gateway/http-auth-utils.ts:111-121 and src/gateway/auth.ts:550-557 accept the identical bearer as a password-mode Gateway credential. The only startup guard, assertHooksTokenSeparateFromGatewayAuth() in src/gateway/startup-auth.ts:224-245, compares hooks.token only against gateway.auth.token, and src/gateway/startup-auth.test.ts:583-599 explicitly documents that matching values are allowed when the gateway runs in password mode. The matching security-audit path in src/security/audit-extra.sync.ts:516-541 likewise only detects hook-token reuse against token-mode gateway auth, so password-mode reuse is not reported. Under the repo trust model, openclaw/SECURITY.md:124-132 says Gateway password auth on /tools/invoke yields full operator scopes and owner semantics, so the shared hook token escapes hook-ingress restrictions and becomes a full Gateway operator credential.

Classification: security-specific

This crosses the documented Gateway auth boundary. openclaw/SECURITY.md states that authenticated Gateway callers are treated as trusted operators and that shared-secret bearer auth on POST /tools/invoke receives the full default operator scope set plus owner semantics. This report does not rely on adversarial multi-tenant sharing, prompt injection, or trusted-local-write preconditions; it shows one hook-ingress credential being accepted on a separate full-operator Gateway auth surface.

Environment

Observed on upstream/main at commit 3d96111a5afe377b529c9bb5a9db510d74607344 by tracing the current hook and Gateway auth code paths. Repro requires any deployment that enables hooks and runs shared-secret Gateway auth in password mode.

Remediation Advice

Reject hooks.token == gateway.auth.password anywhere auth is resolved or reloaded, add a matching security-audit finding for password-mode credential reuse, and keep hook-ingress credentials distinct from Gateway shared-secret operator credentials across HTTP auth checks.

<!-- submission-marker:CR-fmi-hook-ingress-token-unlocks-password-mode-gateway-auth -->

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Hook ingress token unlocks password-mode gateway auth [1 pull requests, 1 comments, 2 participants]