VYPR
Moderate severityNVD Advisory· Published Mar 19, 2026· Updated Mar 25, 2026

OpenClaw < 2026.2.21 - Insecure Control UI Authentication over Plaintext HTTP

CVE-2026-32034

Description

OpenClaw versions prior to 2026.2.21 contain an authentication bypass vulnerability in the Control UI when allowInsecureAuth is explicitly enabled and the gateway is exposed over plaintext HTTP, allowing attackers to bypass device identity and pairing verification. An attacker with leaked or intercepted credentials can obtain high-privilege Control UI access by exploiting the lack of secure authentication enforcement over unencrypted HTTP connections.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.2.212026.2.21

Affected products

1

Patches

1
40a292619e1f

fix: Control UI Insecure Auth Bypass Allows Token-Only Auth Over HTTP (#20684)

https://github.com/openclaw/openclawCoy GeekFeb 20, 2026via ghsa
4 files changed · +32 7
  • CHANGELOG.md+1 0 modified
    @@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
     
     ### Fixes
     
    +- Gateway/Security: require secure context and paired-device checks for Control UI auth even when `gateway.controlUi.allowInsecureAuth` is set, and align audit messaging with the hardened behavior. (#20684) thanks @coygeek.
     - macOS/Build: default release packaging to `BUNDLE_ID=ai.openclaw.mac` in `scripts/package-mac-dist.sh`, so Sparkle feed URL is retained and auto-update no longer fails with an empty appcast feed. (#19750) thanks @loganprit.
     
     - Signal/Outbound: preserve case for Base64 group IDs during outbound target normalization so cross-context routing and policy checks no longer break when group IDs include uppercase characters. (#5578) Thanks @heyhudson.
    
  • src/gateway/server.auth.e2e.test.ts+24 4 modified
    @@ -687,7 +687,7 @@ describe("gateway server auth/connect", () => {
         });
       });
     
    -  test("allows control ui without device identity when insecure auth is enabled", async () => {
    +  test("rejects control ui without device identity even when insecure auth is enabled", async () => {
         testState.gatewayControlUi = { allowInsecureAuth: true };
         const { server, ws, prevToken } = await startServerWithClient("secret", {
           wsHeaders: { origin: "http://127.0.0.1" },
    @@ -702,13 +702,32 @@ describe("gateway server auth/connect", () => {
             mode: GATEWAY_CLIENT_MODES.WEBCHAT,
           },
         });
    -    expect(res.ok).toBe(true);
    +    expect(res.ok).toBe(false);
    +    expect(res.error?.message ?? "").toContain("secure context");
         ws.close();
         await server.close();
         restoreGatewayToken(prevToken);
       });
     
    -  test("allows control ui with device identity when insecure auth is enabled", async () => {
    +  test("rejects control ui password-only auth when insecure auth is enabled", async () => {
    +    testState.gatewayControlUi = { allowInsecureAuth: true };
    +    testState.gatewayAuth = { mode: "password", password: "secret" };
    +    await withGatewayServer(async ({ port }) => {
    +      const ws = await openWs(port, { origin: originForPort(port) });
    +      const res = await connectReq(ws, {
    +        password: "secret",
    +        device: null,
    +        client: {
    +          ...CONTROL_UI_CLIENT,
    +        },
    +      });
    +      expect(res.ok).toBe(false);
    +      expect(res.error?.message ?? "").toContain("secure context");
    +      ws.close();
    +    });
    +  });
    +
    +  test("does not bypass pairing for control ui device identity when insecure auth is enabled", async () => {
         testState.gatewayControlUi = { allowInsecureAuth: true };
         testState.gatewayAuth = { mode: "token", token: "secret" };
         const { writeConfigFile } = await import("../config/config.js");
    @@ -753,7 +772,8 @@ describe("gateway server auth/connect", () => {
                 ...CONTROL_UI_CLIENT,
               },
             });
    -        expect(res.ok).toBe(true);
    +        expect(res.ok).toBe(false);
    +        expect(res.error?.message ?? "").toContain("pairing required");
             ws.close();
           });
         } finally {
    
  • src/gateway/server/ws-connection/message-handler.ts+6 2 modified
    @@ -341,7 +341,9 @@ export function attachGatewayWsMessageHandler(params: {
               isControlUi && configSnapshot.gateway?.controlUi?.allowInsecureAuth === true;
             const disableControlUiDeviceAuth =
               isControlUi && configSnapshot.gateway?.controlUi?.dangerouslyDisableDeviceAuth === true;
    -        const allowControlUiBypass = allowInsecureControlUi || disableControlUiDeviceAuth;
    +        // `allowInsecureAuth` is retained for compatibility, but must not bypass
    +        // secure-context/device-auth requirements.
    +        const allowControlUiBypass = disableControlUiDeviceAuth;
             const device = disableControlUiDeviceAuth ? null : deviceRaw;
     
             const hasDeviceTokenCandidate = Boolean(connectParams.auth?.token && device);
    @@ -428,7 +430,9 @@ export function attachGatewayWsMessageHandler(params: {
     
               if (isControlUi && !allowControlUiBypass) {
                 const errorMessage = "control ui requires HTTPS or localhost (secure context)";
    -            markHandshakeFailure("control-ui-insecure-auth");
    +            markHandshakeFailure("control-ui-insecure-auth", {
    +              insecureAuthConfigured: allowInsecureControlUi,
    +            });
                 sendHandshakeErrorResponse(ErrorCodes.INVALID_REQUEST, errorMessage);
                 close(1008, errorMessage);
                 return;
    
  • src/security/audit.ts+1 1 modified
    @@ -351,7 +351,7 @@ function collectGatewayConfigFindings(
           severity: "critical",
           title: "Control UI allows insecure HTTP auth",
           detail:
    -        "gateway.controlUi.allowInsecureAuth=true allows token-only auth over HTTP and skips device identity.",
    +        "gateway.controlUi.allowInsecureAuth=true is a legacy insecure-auth toggle; Control UI still enforces secure context and device identity unless dangerouslyDisableDeviceAuth is enabled.",
           remediation: "Disable it or switch to HTTPS (Tailscale Serve) or localhost.",
         });
       }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.