Skip to content

fix(gateway): require auth for control ui bootstrap config#70247

Merged
drobison00 merged 6 commits intoopenclaw:mainfrom
drobison00:control-ui-bootstrap-auth
Apr 22, 2026
Merged

fix(gateway): require auth for control ui bootstrap config#70247
drobison00 merged 6 commits intoopenclaw:mainfrom
drobison00:control-ui-bootstrap-auth

Conversation

@drobison00
Copy link
Copy Markdown
Contributor

fix(gateway): require auth for control ui bootstrap config

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: /__openclaw/control-ui-config.json returned bootstrap metadata even when gateway.auth was configured.
  • Why it matters: unauthenticated callers could read server version, assistant identity, embed posture, and local media preview roots.
  • What changed: the bootstrap handler now uses the existing Control UI read-auth helper, server-http now passes the resolved auth context into that handler, and gateway tests cover both unauthorized and authorized bootstrap requests.
  • What did NOT change (scope boundary): no CI, workflow, dependency, or unrelated Control UI route behavior changed.

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
  • Related NVIDIA-dev/openclaw-tracking#497
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: handleControlUiHttpRequest() served the bootstrap config branch without calling authorizeControlUiReadRequest(), and its request options did not accept the auth-related fields used by sibling Control UI read routes.
  • Missing detection / guardrail: bootstrap config tests asserted the anonymous payload shape but did not assert that auth-enabled deployments reject unauthenticated requests.
  • Contributing context (if known): the bootstrap response had already accumulated more host-specific fields, so the missing auth gate exposed more metadata over time.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/control-ui.http.test.ts
  • Scenario the test should lock in: bootstrap config requests return 401 without a valid credential when gateway.auth is enabled and still return 200 with the valid token.
  • Why this is the smallest reliable guardrail: it exercises the exported bootstrap handler directly and covers the server-auth wiring without needing a full running gateway.
  • Existing test that already covers this (if any): none before this patch.
  • If no new test is added, why not: new targeted tests were added in src/gateway/control-ui.http.test.ts.

User-visible / Behavior Changes

  • Gateways with gateway.auth enabled now require valid Control UI read auth before returning /__openclaw/control-ui-config.json.
  • Authenticated Control UI callers continue to receive the bootstrap payload.

Diagram (if applicable)

N/A

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) Yes
  • If any Yes, explain risk + mitigation: bootstrap config data is no longer exposed to unauthenticated callers when gateway auth is configured; the route now uses the same read-auth path as the sibling Control UI read endpoints.

Repro + Verification

Environment

  • OS: Linux 6.8.0-110-generic
  • Runtime/container: Codex workspace shell
  • Model/provider: <operator to fill>
  • Integration/channel (if any): None
  • Relevant config (redacted): gateway.controlUi enabled; gateway.auth.mode=token

Steps

  1. Start the gateway with Control UI enabled and gateway auth configured.
  2. Request GET /__openclaw/control-ui-config.json without an auth credential.
  3. Repeat the same request with a valid bearer token.

Expected

  • Unauthenticated request is rejected.
  • Authenticated request returns the bootstrap config payload.

Actual

  • Targeted gateway tests pass for both unauthorized and authorized bootstrap config requests.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: ran node ./node_modules/vitest/vitest.mjs run --reporter=verbose --config test/vitest/vitest.gateway.config.ts src/gateway/control-ui.http.test.ts src/gateway/control-ui.auto-root.http.test.ts src/gateway/gateway-misc.test.ts and confirmed 3 files / 67 tests passed, including the new bootstrap auth cases.
  • Edge cases checked: valid-token bootstrap reads still return 200; existing direct callers and tests were updated to await the now-async Control UI HTTP handler.
  • What you did not verify: a manual live gateway curl reproduction outside the test harness.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

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

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: other call sites could miss the new async handleControlUiHttpRequest() contract.
  • Mitigation: the gateway server path and direct tests in the touched area were updated to await the handler.
  • Risk: deployments that implicitly relied on anonymous bootstrap reads will now receive auth failures when gateway.auth is enabled.
  • Mitigation: the behavior now matches the sibling Control UI read routes, and the authorized bootstrap path is covered by targeted tests.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: S maintainer Maintainer-authored PR labels Apr 22, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

This PR fixes a missing auth gate on /__openclaw/control-ui-config.json, which previously returned bootstrap metadata (server version, assistant identity, embed posture, local media roots) to unauthenticated callers even when gateway.auth was configured. The fix adds an authorizeControlUiReadRequest call to the bootstrap config branch, passes the required auth context from server-http.ts, and upgrades handleControlUiHttpRequest to async/Promise<boolean>. All existing call sites are correctly updated to await the handler, and new targeted tests verify both the 401 rejection and the 200 authorized path.

Confidence Score: 5/5

Safe to merge — the fix is well-scoped, all call sites are updated, and new tests cover the added auth gate.

All remaining findings are at most P2. The core auth gate is correctly implemented following the same pattern as sibling Control UI read routes. Every call site that uses the now-async handler is properly awaited. New tests cover the unauthorized (401) and authorized (200) bootstrap scenarios. No regressions introduced.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(gateway): require auth for control u..." | Re-trigger Greptile

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b28756c9f2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/gateway/control-ui.ts
@drobison00 drobison00 force-pushed the control-ui-bootstrap-auth branch 2 times, most recently from de300ca to 3a96e29 Compare April 22, 2026 16:15
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a96e29903

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/src/ui/controllers/control-ui-bootstrap.ts Outdated
@drobison00 drobison00 force-pushed the control-ui-bootstrap-auth branch 2 times, most recently from 401355e to 827160a Compare April 22, 2026 17:18
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 827160a697

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/src/ui/controllers/control-ui-bootstrap.ts Outdated
@drobison00 drobison00 force-pushed the control-ui-bootstrap-auth branch from 827160a to 68bd62f Compare April 22, 2026 22:26
@drobison00 drobison00 force-pushed the control-ui-bootstrap-auth branch from 68bd62f to d555597 Compare April 22, 2026 22:48
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 22, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🔵 Low Auth retry loop can amplify failed-auth attempts and trigger rate-limit lockouts
1. 🔵 Auth retry loop can amplify failed-auth attempts and trigger rate-limit lockouts
Property Value
Severity Low
CWE CWE-307
Location ui/src/ui/controllers/control-ui-bootstrap.ts:46-60

Description

loadControlUiBootstrapConfig retries the bootstrap request with multiple shared-secret candidates (deviceToken, settings.token, password) when it receives a 401/403. Each retry results in an additional authentication attempt against the gateway.

If the gateway’s AuthRateLimiter is enabled, each wrong candidate will typically call recordFailure(...) server-side, so a single UI bootstrap action can:

  • Multiply failed-auth events (up to 3 failures per user action)
  • Accelerate lockout/DoS against legitimate users who have stale credentials stored (e.g., old settings.token plus a changed password)
  • Increase the effective guess rate for an attacker who can trigger the bootstrap fetch repeatedly (client performs multiple attempts per trigger)

Vulnerable code:

const attempts: string[] = authCandidates.length > 0 ? authCandidates : [""];
for (const candidate of attempts) {
  ...
  res = await fetch(url, { method: "GET", headers, credentials: "same-origin" });
  if (res.ok) break;
  if (res.status !== 401 && res.status !== 403) return;
}

Recommendation

Reduce the number of automatic shared-secret retries and/or avoid counting multiple failures toward lockout for a single UI action.

Options:

  1. Only retry once (max 2 attempts total) and only when there’s strong evidence the first credential is stale (e.g., prefer current session credential and do not try older persisted ones).

  2. Add client-side backoff / retry gating so repeated UI bootstrap attempts within a short window do not keep generating multiple auth failures.

  3. Server-side: if you keep the retry behavior, consider adding a mechanism to treat a small burst of failures within one request chain as a single failure (or delay responses) for the bootstrap endpoint.

Example (client: cap retries to 1):

const authCandidates = sameOrigin ? resolveControlUiAuthCandidates(state) : [];
const attempts = authCandidates.slice(0, 2); // at most one retry

Analyzed PR: #70247 at commit d555597

Last updated on: 2026-04-22T22:51:04Z

@drobison00 drobison00 merged commit 2321d67 into openclaw:main Apr 22, 2026
70 of 73 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5555976a1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/src/ui/app-gateway.ts
Comment on lines +296 to +298
void loadControlUiBootstrapConfig(
host as unknown as Parameters<typeof loadControlUiBootstrapConfig>[0],
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid clobbering session identity on hello bootstrap refresh

Triggering loadControlUiBootstrapConfig inside onHello races with loadAssistantIdentity, and both write assistantName/assistantAvatar/assistantAgentId on the same host object. The bootstrap response is derived from config-level identity (via src/gateway/server-http.ts passing resolveAssistantIdentity({ cfg }).agentId into the bootstrap handler), not the active session’s agent, so in non-default sessions this extra fetch can overwrite the correct per-session identity if it finishes last.

Useful? React with 👍 / 👎.

medikoo pushed a commit to medikoo/openclaw that referenced this pull request Apr 24, 2026
…70247)

* fix(gateway): require auth for control ui bootstrap config

* fix(ui): send auth on bootstrap fetch

* fix(ui): keep bootstrap auth same-origin

* fix(ui): refresh bootstrap after auth hello

* docs(changelog): note control ui bootstrap auth

* fix(ui): retry bootstrap auth with alternate shared secret on 401
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…70247)

* fix(gateway): require auth for control ui bootstrap config

* fix(ui): send auth on bootstrap fetch

* fix(ui): keep bootstrap auth same-origin

* fix(ui): refresh bootstrap after auth hello

* docs(changelog): note control ui bootstrap auth

* fix(ui): retry bootstrap auth with alternate shared secret on 401
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request May 7, 2026
…70247)

* fix(gateway): require auth for control ui bootstrap config

* fix(ui): send auth on bootstrap fetch

* fix(ui): keep bootstrap auth same-origin

* fix(ui): refresh bootstrap after auth hello

* docs(changelog): note control ui bootstrap auth

* fix(ui): retry bootstrap auth with alternate shared secret on 401
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…70247)

* fix(gateway): require auth for control ui bootstrap config

* fix(ui): send auth on bootstrap fetch

* fix(ui): keep bootstrap auth same-origin

* fix(ui): refresh bootstrap after auth hello

* docs(changelog): note control ui bootstrap auth

* fix(ui): retry bootstrap auth with alternate shared secret on 401
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant