Mar 14, 2026·7 min read·2 visits
A 'Check-Then-Limit' logic flaw in OpenClaw's Zalo webhook handler allows attackers to bypass rate limiting. Unauthenticated requests that fail authentication do not consume the rate limit budget, enabling rapid brute-force attacks to discover the webhook secret.
OpenClaw versions prior to 2026.3.12 contain a logic flaw in the Zalo webhook handler where rate limiting is applied after authentication validation. This allows unauthenticated attackers to bypass request throttling and conduct unbounded brute-force attacks against the webhook secret token.
The OpenClaw ecosystem (formerly Moltbot/ClawdBot) provides integration capabilities with various third-party messaging services, including Zalo. These integrations rely on webhook endpoints to receive asynchronous event notifications. To secure these endpoints against unauthorized event injection, OpenClaw requires an authentication token passed via the x-bot-api-secret-token HTTP header.
A structural logic flaw exists in the sequence of operations within the Zalo extension's webhook handler (extensions/zalo/src/monitor.webhook.ts). The application processes incoming HTTP requests by first attempting to authenticate the provided secret token before applying any rate-limiting mechanisms. This implementation error aligns with CWE-307: Improper Restriction of Excessive Authentication Attempts.
Because the application terminates the request lifecycle and returns a 401 Unauthorized response immediately upon authentication failure, the execution flow never reaches the rate-limiting logic. Consequently, an attacker can submit an arbitrary number of incorrect tokens without ever consuming their rate-limit budget or triggering a 429 Too Many Requests response.
The vulnerability stems from an incorrect ordering of security controls within the handleZaloWebhookRequest function. In software design, resource exhaustion controls and rate limiters must generally execute prior to computationally expensive or sensitive operations, including authentication checks. The affected version reverses this secure default.
Upon receiving a webhook request, the system invokes resolveWebhookTargetWithAuthOrRejectSync to validate the x-bot-api-secret-token header. If the token is invalid or missing, this function forces an early exit, dispatching a 401 Unauthorized status code to the client. The request processing is thus fully terminated at the authentication phase.
The rate-limiting function, applyBasicWebhookRequestGuards, is positioned chronologically after this authentication block in the source code. It is only invoked if resolveWebhookTargetWithAuthOrRejectSync returns successfully. As a result, invalid authentication attempts do not increment the rate-limiter counters, effectively disabling brute-force protection for the authentication endpoint.
Compounding this issue, the original rate limiter relied directly on the req.socket.remoteAddress property to identify the client IP address. In environments where OpenClaw is deployed behind a reverse proxy or load balancer, this value reflects the proxy's internal IP rather than the true external client IP. This secondary flaw prevents the system from distinguishing individual external actors, further undermining any residual rate-limiting efficacy.
The vulnerable execution path in extensions/zalo/src/monitor.webhook.ts clearly demonstrates the 'Check-Then-Limit' anti-pattern. Analyzing the patch introduced in PR #44173 (commit f96ba87f033a14183fa0ede912df3a592eef55ff) reveals the necessary structural changes to remediate the vulnerability.
Prior to the patch, the code fetched the authentication token and validated it before applying rate limits. The patch fundamentally reorders this logic. First, it introduces robust IP resolution handling that processes X-Forwarded-For and X-Real-IP headers, provided they originate from configured trusted proxies. This prevents IP spoofing while correctly identifying clients behind reverse proxies.
// Patched logic from extensions/zalo/src/monitor.webhook.ts
+ const clientIp = resolveClientIp({
+ remoteAddr: req.socket.remoteAddress,
+ forwardedFor: headerValue(req.headers["x-forwarded-for"]),
+ realIp: headerValue(req.headers["x-real-ip"]),
+ trustedProxies,
+ allowRealIpFallback,
+ }) ?? "unknown";
+
+ const rateLimitKey = `${path}:${clientIp}`;
+
+ // NEW: Rate limit BEFORE authentication
+ if (!applyBasicWebhookRequestGuards({ req, res, rateLimiter, rateLimitKey })) {
+ return true; // Returns 429
+ }
const headerToken = String(req.headers["x-bot-api-secret-token"] ?? "");
const target = resolveWebhookTargetWithAuthOrRejectSync({ ... });By establishing the client IP securely and constructing a unique rateLimitKey based on the requested path and the resolved IP, the system can now track request frequencies accurately. Most crucially, the invocation of applyBasicWebhookRequestGuards is moved ahead of resolveWebhookTargetWithAuthOrRejectSync. This ensures that all requests, regardless of their authentication status, increment the rate-limit counter.
Exploitation of GHSA-5M9R-P9G7-679C is highly deterministic and requires no specialized tools beyond a standard HTTP client capable of high-concurrency requests. An attacker first identifies the target OpenClaw Zalo webhook endpoint, which typically resides at a predictable URI structure such as /hook-zalo.
The attacker then initiates a high-volume credential stuffing or dictionary attack against the x-bot-api-secret-token HTTP header. Because the rate limiter is bypassed for failed attempts, the attacker can execute these requests at the maximum throughput the network and server infrastructure can sustain.
# Conceptual Nuclei template logic demonstrating the detection mechanism
id: GHSA-5M9R-P9G7-679C-Detection
info:
name: OpenClaw Zalo Webhook Rate Limit Bypass
severity: medium
requests:
- method: POST
path:
- "{{BaseURL}}/hook-zalo"
headers:
x-bot-api-secret-token: "invalid-{{randstr}}"
count: 150
matchers:
- type: status
status:
- 401During the attack, the threat actor monitors the HTTP response codes. Vulnerable systems will consistently return 401 Unauthorized for every invalid guess. A successful guess is immediately identifiable when the server responds with a 200 OK or a 415 Unsupported Media Type (if the POST body payload is malformed but the authentication succeeded). The absence of a 429 Too Many Requests response during the flood confirms the system is vulnerable.
The architectural flaw can be visualized by tracing the request lifecycle through the webhook handler. The critical failure occurs when the execution branches at the authentication gate, returning a response before encountering the rate limiting module.
This execution topology demonstrates why traditional edge-based monitoring might fail to detect the severity of the attack if the WAF relies solely on application-level signaling for rate limiting. The immediate return forces the infrastructure to handle the full brunt of the brute-force traffic without application-layer backpressure.
The vulnerability carries a CVSS v3.1 base score of 5.3 (Medium), reflecting a low-complexity network attack with a partial impact on confidentiality. While the vulnerability does not directly permit arbitrary code execution or total system compromise, it fundamentally undermines the access control mechanism protecting the webhook integration.
Successful exploitation allows an attacker to discover the secret token required to interact with the Zalo webhook endpoint. Once compromised, the attacker can spoof arbitrary Zalo events and inject them directly into the OpenClaw system. This can lead to logic abuse, data corruption within the context of the bot's operation, or social engineering attacks executed via the bot's messaging capabilities.
The secondary impact is resource exhaustion. Because the application processes each authentication failure without throttling, a sustained volumetric attack could consume significant CPU and memory resources, potentially degrading the performance of the OpenClaw instance for legitimate users and other active integrations.
The primary remediation for this vulnerability is to upgrade the npm/openclaw package to version 2026.3.12 or later. This release contains the logic reordering and improved IP resolution mechanisms necessary to correctly apply rate limits to all incoming requests.
For systems where immediate patching is not feasible, security teams should implement edge-level rate limiting via a Web Application Firewall (WAF) or reverse proxy (e.g., NGINX, HAProxy). These edge devices can be configured to throttle requests to the /hook-zalo endpoint based on the true client IP address, regardless of the HTTP response code returned by the backend OpenClaw application.
Administrators must also verify their reverse proxy configurations. The application relies on trustedProxies settings to safely parse X-Forwarded-For and X-Real-IP headers. If these arrays are misconfigured or empty in the patched version, the application may fallback to unknown or process spoofed headers, potentially creating new rate-limit evasion vectors. Furthermore, any organization that detects anomalous 401 Unauthorized traffic targeting their webhooks should immediately rotate their x-bot-api-secret-token values.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
npm/openclaw OpenClaw | < 2026.3.12 | 2026.3.12 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-307 |
| Attack Vector | Network |
| CVSS v3.1 | 5.3 |
| Impact | Confidentiality (Partial) |
| Exploit Status | Proof of Concept (PoC) |
| CISA KEV | Not Listed |
Improper Restriction of Excessive Authentication Attempts