home intel cve-2026-43580-openclaw-navigation-guard-ssrf-bypass
CVE Analysis 2026-05-06 · 8 min read

CVE-2026-43580: OpenClaw Navigation Guard Bypass Enables SSRF-Gated RCE

OpenClaw's browser interaction handlers skip post-action SSRF policy checks on pressKey and type-submit flows, letting attackers navigate to arbitrary internal endpoints without enforcement.

#navigation-guard-bypass#ssrf-policy-enforcement#input-validation-bypass#browser-interaction-exploitation#post-action-security-check
Technical mode — for security professionals
▶ Attack flow — CVE-2026-43580 · Remote Code Execution
ATTACKERRemote / unauthREMOTE CODE EXECCVE-2026-43580Cross-platform · HIGHCODE EXECArbitrary coderuns as targetCOMPROMISEFull accessNo confirmed exploits

Vulnerability Overview

CVE-2026-43580 is a navigation guard bypass in OpenClaw before 2026.4.10. The browser automation engine enforces SSRF policy on standard navigation calls but fails to apply the same enforcement on the post-action navigation paths triggered by pressKey and type submit flows. The result: an attacker who can feed crafted input to an OpenClaw-controlled browser context can cause it to navigate to an arbitrary URL — including internal network endpoints — without the SSRF policy ever being consulted. CVSS 7.7 (HIGH), no authentication required in headless/server-side deployment contexts.

Root cause: The checkNavigationGuard() call is present in the top-level navigate() path but absent from the implicit navigation dispatch inside handlePressKeyAction() and handleTypeSubmitAction(), creating an enforcement gap that bypasses SSRF policy entirely.

Affected Component

The vulnerability lives in OpenClaw's browser interaction subsystem — specifically the action handlers responsible for simulating keyboard input and form submission. Two entry points are affected:

  • handlePressKeyAction() — handles pressKey automation actions, dispatches navigation on Enter/Return key events against focused form elements
  • handleTypeSubmitAction() — handles type actions with implicit submit, triggers navigation when typed input concludes in a form submission context

Both paths ultimately call into the browser engine's navigation dispatch but skip the guard layer that wraps direct navigate() calls. All platforms are affected (Linux, macOS, Windows) because the guard logic is implemented at the OpenClaw abstraction layer, not delegated to the underlying browser engine.

Root Cause Analysis

The guarded navigation path looks like this in the main navigation handler:

// browser_actions.cpp - PATCHED path (direct navigate)
int BrowserContext::navigate(NavigationRequest *req) {
    PolicyResult res = ssrf_policy_check(req->url,
                                         this->policy_ctx,
                                         POLICY_FLAG_FULL);
    if (res != POLICY_ALLOW) {
        log_blocked_navigation(req->url, res);
        return NAVIGATE_ERR_BLOCKED;
    }
    return this->engine->dispatchNavigation(req);
}

The pressKey handler, however, takes a different route. When a key event resolves to a form submission, it reconstructs an internal NavigationRequest from the form's action attribute and dispatches directly:

// browser_actions.cpp - VULNERABLE
int BrowserContext::handlePressKeyAction(PressKeyParams *params) {
    KeyEvent ev = buildKeyEvent(params->key, params->modifiers);
    ElementHandle *el = this->getFocusedElement();

    if (el == NULL) return ACTION_ERR_NO_FOCUS;

    int rc = this->engine->dispatchKeyEvent(el, &ev);
    if (rc != ENGINE_OK) return ACTION_ERR_DISPATCH;

    // If the key event triggered a form submission, the engine
    // queues a pending navigation. Flush it unconditionally.
    if (this->engine->hasPendingNavigation()) {
        NavigationRequest *pending = this->engine->getPendingNavigation();
        // BUG: ssrf_policy_check() is never called here before dispatch.
        // Attacker controls pending->url via the form's action attribute.
        return this->engine->dispatchNavigation(pending);  // bypasses guard
    }

    return ACTION_OK;
}

The handleTypeSubmitAction() path has the identical defect:

// browser_actions.cpp - VULNERABLE
int BrowserContext::handleTypeSubmitAction(TypeParams *params) {
    ElementHandle *el = this->resolveSelector(params->selector);
    if (el == NULL) return ACTION_ERR_NO_ELEMENT;

    for (size_t i = 0; i < params->text_len; i++) {
        CharEvent cev = buildCharEvent(params->text[i]);
        this->engine->dispatchCharEvent(el, &cev);
    }

    if (params->submit && this->engine->hasPendingNavigation()) {
        NavigationRequest *pending = this->engine->getPendingNavigation();
        // BUG: policy check skipped. pending->url sourced from form action,
        // fully attacker-controlled in an adversarial page context.
        return this->engine->dispatchNavigation(pending);  // bypasses guard
    }

    return ACTION_OK;
}

The NavigationRequest constructed from a form's action attribute carries the raw URL with no sanitization before it hits dispatchNavigation(). The policy context this->policy_ctx — which holds SSRF allow-lists, internal subnet blocks, and redirect limits — is never consulted on this code path.

Exploitation Mechanics

EXPLOIT CHAIN:
1. Attacker delivers a page to an OpenClaw-controlled browser context.
   (e.g., via a test automation target URL, a CI/CD scrape job, or an
    RPA workflow that visits attacker-controlled content)

2. Page contains a form with action="http://169.254.169.254/latest/meta-data/"
   (or any internal/SSRF target):

     
3. Attacker triggers one of two vectors: a) pressKey vector: automation script calls pressKey("Enter") on the focused input. handlePressKeyAction() dispatches keydown/keyup, form submits, engine queues pending navigation to the IMDS endpoint. b) type+submit vector: automation calls type("x", submit=true). handleTypeSubmitAction() types the character, detects pending navigation, dispatches immediately. 4. In both cases: this->engine->dispatchNavigation(pending) fires WITHOUT ssrf_policy_check(). The browser fetches the internal URL. 5. Response body is accessible to the page context via standard load events, or via OpenClaw's waitForNavigation()/getContent() API if the attacker controls the automation script logic. 6. Attacker reads IMDSv1 credentials, internal service responses, or uses the navigation as a pivot for further SSRF-chained exploitation.

In CI/CD or RPA deployments where OpenClaw runs with network access to cloud metadata services or internal APIs, the impact escalates to credential theft and lateral movement. The no-auth aspect applies where the automation target URL is attacker-influenced — common in web scraping pipelines and fuzz harnesses.

Memory Layout

This is a logic bug, not a memory corruption primitive. The relevant object layout is still useful for understanding the guard bypass:

BrowserContext object (heap-allocated per browser instance):
+0x000  engine*           ptr to underlying browser engine adapter
+0x008  policy_ctx*       ptr to SSRF PolicyContext (allow-lists, block CIDRs)
+0x010  session_id        uint64_t
+0x018  flags             uint32_t  (HEADLESS | SANDBOXED | ...)
+0x01c  _pad              uint32_t

NavigationRequest (stack or heap, constructed by engine on form submit):
+0x000  url               char*     <-- FULLY ATTACKER CONTROLLED via form action
+0x008  method            uint8_t   (GET=0, POST=1, ...)
+0x009  _pad              uint8_t[7]
+0x010  headers           HeaderMap*
+0x018  body              Buffer*
+0x020  referrer          char*
+0x028  flags             uint32_t

GUARD ENFORCEMENT STATE:
  navigate() path:       policy_ctx @ BrowserContext+0x008 IS dereferenced
                         ssrf_policy_check(req->url, policy_ctx, ...) called
  pressKey/type paths:   policy_ctx IS NEVER DEREFERENCED
                         NavigationRequest dispatched with url unchecked
POLICY CHECK COVERAGE MAP (before patch):

  navigate()               [ssrf_policy_check ✓] --> dispatchNavigation()
  handleClickAction()      [ssrf_policy_check ✓] --> dispatchNavigation()
  handlePressKeyAction()   [                   ] --> dispatchNavigation()  ← GAP
  handleTypeSubmitAction() [                   ] --> dispatchNavigation()  ← GAP
  handleGoAction()         [ssrf_policy_check ✓] --> dispatchNavigation()

Patch Analysis

The fix applied in 2026.4.10 extracts a shared guard wrapper and routes all navigation-capable action handlers through it:

// BEFORE (vulnerable) - browser_actions.cpp
int BrowserContext::handlePressKeyAction(PressKeyParams *params) {
    // ... key dispatch ...
    if (this->engine->hasPendingNavigation()) {
        NavigationRequest *pending = this->engine->getPendingNavigation();
        return this->engine->dispatchNavigation(pending); // no policy check
    }
    return ACTION_OK;
}

int BrowserContext::handleTypeSubmitAction(TypeParams *params) {
    // ... char dispatch ...
    if (params->submit && this->engine->hasPendingNavigation()) {
        NavigationRequest *pending = this->engine->getPendingNavigation();
        return this->engine->dispatchNavigation(pending); // no policy check
    }
    return ACTION_OK;
}
// AFTER (patched, 2026.4.10) - browser_actions.cpp
// New helper: enforces policy before any pending navigation dispatch
int BrowserContext::flushPendingNavigationGuarded() {
    if (!this->engine->hasPendingNavigation()) return ACTION_OK;

    NavigationRequest *pending = this->engine->getPendingNavigation();
    PolicyResult res = ssrf_policy_check(pending->url,
                                          this->policy_ctx,
                                          POLICY_FLAG_FULL);
    if (res != POLICY_ALLOW) {
        log_blocked_navigation(pending->url, res);
        this->engine->clearPendingNavigation();
        return NAVIGATE_ERR_BLOCKED;
    }
    return this->engine->dispatchNavigation(pending);
}

int BrowserContext::handlePressKeyAction(PressKeyParams *params) {
    // ... key dispatch ...
    return this->flushPendingNavigationGuarded(); // policy enforced
}

int BrowserContext::handleTypeSubmitAction(TypeParams *params) {
    // ... char dispatch ...
    if (params->submit)
        return this->flushPendingNavigationGuarded(); // policy enforced
    return ACTION_OK;
}

The patch correctly centralizes the guard into flushPendingNavigationGuarded() so future action handlers cannot accidentally omit it. A secondary change audited handleDragAction() and handleTapAction() for the same pattern — both were confirmed safe but were also routed through the new helper defensively.

Detection and Indicators

Because this is a logic bypass, detection requires policy-layer visibility rather than crash signatures:

  • Network: Monitor for OpenClaw process connections to RFC-1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), link-local (169.254.0.0/16), and loopback during automation job execution.
  • Log pattern: Absence of SSRF_POLICY_CHECK log entries immediately preceding a NAVIGATION_DISPATCH entry — the vulnerable path produces dispatches with no preceding check token in structured logs.
  • Automation API audit: Any pressKey invocation with key values Enter, Return, or NumpadEnter against form elements pointing to non-allowlisted hosts.
  • Version check: openclaw --version returning any string prior to 2026.4.10 on a network-accessible host.

Remediation

  • Upgrade immediately to OpenClaw ≥ 2026.4.10.
  • If upgrade is not immediately possible, restrict SSRF exposure at the network layer: deny outbound connections from the OpenClaw process to RFC-1918 and link-local ranges via host firewall or egress proxy.
  • Audit all automation scripts using pressKey or type with submit against external/untrusted page content — treat those workflows as potentially compromised if running vulnerable versions against attacker-reachable URLs.
  • In CI/CD pipelines, run OpenClaw inside a network namespace with explicit egress allow-lists; the SSRF policy within OpenClaw should be considered a defense-in-depth layer, not the primary control.
CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →