CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-C37P-4QQG-3P76
5.8

OpenClaw's Open Door: The 'Convenience' Flag That Bypassed Auth

Alon Barad
Alon Barad
Software Engineer

Feb 18, 2026·5 min read·12 visits

PoC Available

Executive Summary (TL;DR)

OpenClaw introduced a configuration flag to help developers test Twilio webhooks over ngrok. Instead of fixing header validation, the flag implemented a hardcoded `return true` bypass for signature checks. This allows attackers to forge webhooks and trigger unauthorized voice events on affected instances.

In the world of programmable voice, verifying webhooks is critical—unless you're using OpenClaw's 'ngrok compatibility' mode. A vulnerability in the `openclaw` npm package allowed attackers to completely bypass Twilio signature verification by exploiting a developer convenience flag designed for local testing. By effectively telling the server 'it's okay, I'm using ngrok,' the application would skip cryptographic checks entirely, allowing unauthenticated actors to forge incoming voice calls and manipulate call flows.

The Hook: Convenience is the Enemy of Security

Webhook verification is a pain. If you've ever developed a Twilio integration locally, you know the struggle: Twilio signs requests based on the absolute URL they think they are hitting. But when you are sitting behind an ngrok tunnel on your laptop, the Host header, X-Forwarded-Proto, and the actual URL often get mangled or mismatched. The signature validation fails, not because you are being hacked, but because the internet is messy.

OpenClaw, an open-source programmable voice platform, tried to solve this 'developer experience' friction. The goal was noble: allow developers using the free tier of ngrok (which inserts its own interstitial warning pages and messes with headers) to test their voice flows without tearing their hair out over HMAC failures.

However, in security, the road to hell is paved with 'temporary workarounds'. Instead of correctly reconstructing the complex header logic required to validate a signature through a proxy, the developers opted for a much simpler solution: a literal 'Get Out of Jail Free' card.

The Flaw: A 'Works on My Machine' Vulnerability

The vulnerability lies in extensions/voice-call/src/webhook-security.ts. The logic was intended to handle the disparity between the public ngrok URL and the local express server's perception of the request.

The implementation of tunnel.allowNgrokFreeTierLoopbackBypass was catastrophically simple. It didn't relax the rules; it removed the game board entirely. The code checked for three things:

  1. Is the request coming to an .ngrok-free.app or .ngrok.io domain?
  2. Is the configuration flag enabled?
  3. Is the request originating from a loopback address (which it always does when using the ngrok agent locally)?

If these three stars aligned, the application short-circuited the entire verification process. It didn't try to validate the signature with a different strategy. It just returned ok: true. This is the cryptographic equivalent of a bouncer checking if you're wearing sneakers, and if so, letting you into the club without checking ID.

The Code: The 'Return True' Disaster

Let's look at the smoking gun. This isn't a complex buffer overflow or a race condition. It is a logic error that is painfully easy to read.

The Vulnerable Code:

// extensions/voice-call/src/webhook-security.ts
 
const isNgrokFreeTier = verificationUrl.includes(".ngrok-free.app") || verificationUrl.includes(".ngrok.io");
 
// The Fatal Flaw
if (isNgrokFreeTier && options?.allowNgrokFreeTierLoopbackBypass && isLoopback) {
    console.warn("[voice-call] Twilio signature validation failed (ngrok free tier compatibility, loopback only)");
    // BYPASS!
    return {
      ok: true,
      reason: "ngrok free tier compatibility mode (loopback only)",
      verificationUrl,
      isNgrokFreeTier: true,
    };
}

The Fix (Commit ff11d87): The patch removes this short-circuit entirely. Instead of skipping verification, the flag now instructs the verification logic to trust the X-Forwarded headers only when on loopback, allowing the server to reconstruct the correct URL that Twilio signed, and then actually verify the HMAC.

// The fix logic: Don't skip, just adjust the URL construction
if (isLoopback && options?.allowNgrokFreeTierLoopbackBypass) {
    // Use headers to reconstruct the public URL correctly
    // Then proceed to STANDARD cryptographic verification
}

The Exploit: Phoning Home (Literally)

Exploiting this is trivial if the target environment allows it. The attack relies on the fact that when ngrok (the software) forwards a request to your local machine, the connection to your app comes from 127.0.0.1 (loopback). The code trusts the source IP because it assumes loopback is safe.

The Attack Chain:

  1. Recon: Identification of an OpenClaw instance. The default ngrok warning page or specific OpenClaw error headers might give it away.
  2. Configuration Guessing: The attacker hopes the developer left allowNgrokFreeTierLoopbackBypass: true enabled (common in staging environments).
  3. The Payload: The attacker constructs a POST request to /webhooks/voice. They include any X-Twilio-Signature header (it can be garbage, e.g., X-Twilio-Signature: aaaaa).
  4. Execution: The attacker sends the request to the public ngrok URL.

Why it works: OpenClaw sees the request coming from the ngrok agent (localhost). It sees the domain is ngrok.io. It sees the flag is on. It ignores the garbage signature and processes the request.

The attacker can now simulate an incoming call, injecting malicious TwiML (Twilio Markup Language) to record audio, redirect calls, or harass users, all while billing the victim's Twilio account.

The Fix: Trust, But Verify

The remediation logic in version 2026.2.14 is a lesson in how to handle proxies correctly. You never bypass authentication because the network topology is hard; you adapt the authentication to the topology.

The developers removed the return { ok: true } block. They replaced it with logic that says: "If we are on loopback and in compatibility mode, we will trust the X-Forwarded-Proto and X-Forwarded-Host headers to tell us what the real URL is."

This allows the application to reconstruct the exact string that Twilio signed (https://my-tunnel.ngrok.io/webhook) rather than the internal string (http://localhost:3000/webhook), causing the HMAC calculation to match and the signature to pass naturally. Security is restored, and convenience is maintained—without leaving the door wide open.

Official Patches

OpenClawGitHub Commit Diff

Fix Analysis (1)

Technical Appendix

CVSS Score
5.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L

Affected Systems

openclaw npm packageOpenClaw Voice Call Extension

Affected Versions Detail

Product
Affected Versions
Fixed Version
openclaw
openclaw
<= 2026.2.132026.2.14
AttributeDetail
CWE IDCWE-347
Attack VectorNetwork
CVSS Score5.8 (Medium)
ImpactIntegrity Loss (Auth Bypass)
Exploit StatusPoC Available
Affected Componentwebhook-security.ts

MITRE ATT&CK Mapping

T1557Adversary-in-the-Middle
Credential Access
T1588.006Obtain Capabilities: Vulnerabilities
Resource Development
CWE-347
Improper Verification of Cryptographic Signature

Improper Verification of Cryptographic Signature

Known Exploits & Detection

InternalProof of concept involving manual POST requests to ngrok-tunneled instances.

Vulnerability Timeline

Vulnerability reported by @p80n-sec
2026-02-14
Patch committed (ff11d87)
2026-02-14
Public Advisory & Release
2026-02-18

References & Sources

  • [1]GHSA Advisory
  • [2]OSV Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.