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

OpenClaw < 2026.2.21 - Arbitrary Local File Read via Browser Navigation Guard

CVE-2026-32008

Description

OpenClaw versions prior to 2026.2.21 contain an improper URL scheme validation vulnerability in the assertBrowserNavigationAllowed() function that allows authenticated users with browser-tool access to navigate to file:// URLs. Attackers can exploit this by accessing local files readable by the OpenClaw process user through browser snapshot and extraction actions to exfiltrate sensitive data.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.2.212026.2.21

Affected products

1

Patches

1
220bd95eff68

fix(browser): block non-network navigation schemes

https://github.com/openclaw/openclawPeter SteinbergerFeb 21, 2026via ghsa
3 files changed · +41 2
  • CHANGELOG.md+1 0 modified
    @@ -34,6 +34,7 @@ Docs: https://docs.openclaw.ai
     - 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.
     - Docker/Security: run E2E and install-sh test images as non-root by adding appuser directives. Thanks @thewilloftheshadow.
     - Skills/Security: sanitize skill env overrides to block unsafe runtime injection variables and only allow sensitive keys when declared in skill metadata, with warnings for suspicious values. Thanks @thewilloftheshadow.
    +- Security/Browser: block non-network browser navigation protocols (including `file:`, `data:`, and `javascript:`) while preserving `about:blank`, preventing local file reads via browser tool navigation. This ships in the next npm release. Thanks @q1uf3ng for reporting.
     - Security/Gateway/Hooks: block `__proto__`, `constructor`, and `prototype` traversal in webhook template path resolution to prevent prototype-chain payload data leakage in `messageTemplate` rendering. (#22213) Thanks @SleuthCo.
     - Security/OpenClawKit/UI: prevent injected inbound user context metadata blocks from leaking into chat history in TUI, webchat, and macOS surfaces by stripping all untrusted metadata prefixes at display boundaries. (#22142) Thanks @Mellowambience, @vincentkoc.
     - Security/OpenClawKit/UI: strip inbound metadata blocks from user messages in TUI rendering while preserving user-authored content. (#22345) Thanks @kansodata, @vincentkoc.
    
  • src/browser/navigation-guard.test.ts+33 1 modified
    @@ -19,14 +19,46 @@ describe("browser navigation guard", () => {
         ).rejects.toBeInstanceOf(SsrFBlockedError);
       });
     
    -  it("allows non-network schemes", async () => {
    +  it("allows about:blank", async () => {
         await expect(
           assertBrowserNavigationAllowed({
             url: "about:blank",
           }),
         ).resolves.toBeUndefined();
       });
     
    +  it("blocks file URLs", async () => {
    +    await expect(
    +      assertBrowserNavigationAllowed({
    +        url: "file:///etc/passwd",
    +      }),
    +    ).rejects.toBeInstanceOf(InvalidBrowserNavigationUrlError);
    +  });
    +
    +  it("blocks data URLs", async () => {
    +    await expect(
    +      assertBrowserNavigationAllowed({
    +        url: "data:text/html,<h1>owned</h1>",
    +      }),
    +    ).rejects.toBeInstanceOf(InvalidBrowserNavigationUrlError);
    +  });
    +
    +  it("blocks javascript URLs", async () => {
    +    await expect(
    +      assertBrowserNavigationAllowed({
    +        url: "javascript:alert(1)",
    +      }),
    +    ).rejects.toBeInstanceOf(InvalidBrowserNavigationUrlError);
    +  });
    +
    +  it("blocks non-blank about URLs", async () => {
    +    await expect(
    +      assertBrowserNavigationAllowed({
    +        url: "about:srcdoc",
    +      }),
    +    ).rejects.toBeInstanceOf(InvalidBrowserNavigationUrlError);
    +  });
    +
       it("allows blocked hostnames when explicitly allowed", async () => {
         const lookupFn = createLookupFn("127.0.0.1");
         await expect(
    
  • src/browser/navigation-guard.ts+7 1 modified
    @@ -5,6 +5,7 @@ import {
     } from "../infra/net/ssrf.js";
     
     const NETWORK_NAVIGATION_PROTOCOLS = new Set(["http:", "https:"]);
    +const SAFE_NON_NETWORK_URLS = new Set(["about:blank"]);
     
     export class InvalidBrowserNavigationUrlError extends Error {
       constructor(message: string) {
    @@ -42,7 +43,12 @@ export async function assertBrowserNavigationAllowed(
       }
     
       if (!NETWORK_NAVIGATION_PROTOCOLS.has(parsed.protocol)) {
    -    return;
    +    if (SAFE_NON_NETWORK_URLS.has(parsed.href)) {
    +      return;
    +    }
    +    throw new InvalidBrowserNavigationUrlError(
    +      `Navigation blocked: unsupported protocol "${parsed.protocol}"`,
    +    );
       }
     
       await resolvePinnedHostnameWithPolicy(parsed.hostname, {
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

4

News mentions

0

No linked articles in our index yet.