CVE-2026-28470 — OpenClaw versions prior to 2026.2.2 contain an exec approvals (must be enabled) allowlist…¶
Key facts
CVE-2026-28470 is a Critical (9.8) vulnerability: OpenClaw versions prior to 2026.2.2 contain an exec approvals (must be enabled) allowlist…. This entry ships ready-to-deploy detection and prevention rules (Snort, YARA, Nginx, Apache, Sigma) plus a detection-only PoC and a Docker test lab.
| CVE | CVE-2026-28470 |
| Severity | Critical (9.8) |
| Detection / prevention | Snort, YARA, Nginx, Apache, Sigma |
| PoC | poc.py |
| Source | 2026/CVE-2026-28470/ |
Details¶
CVE-2026-28470 is a Critical (9.8) vulnerability: OpenClaw versions prior to 2026.2.2 contain an exec approvals (must be enabled) allowlist…. This entry ships a detection-only proof-of-concept (PoC), a Docker test lab, and ready-to-deploy detection and prevention rules (Snort, YARA, Nginx, Apache) — see Detection and prevention below. Source: NVD record.
English | 한국어
Description¶
OpenClaw versions prior to 2026.2.2 contain an exec approvals (must be enabled) allowlist bypass vulnerability that allows attackers to execute arbitrary commands by injecting command substitution syntax. Attackers can bypass the allowlist protection by embedding unescaped $() or backticks inside double-quoted strings to execute unauthorized commands.
Vulnerability Details¶
| Property | Value |
|---|---|
| CVE ID | CVE-2026-28470 |
| Type | RCE |
| CVSS Score | 9.8 |
Proof of Concept¶
Download¶
# Download PoC script
curl -O https://raw.githubusercontent.com/fankh/vulnerability-poc/main/2026/CVE-2026-28470/poc.py
Usage¶
# Run PoC against target
python3 poc.py --target <TARGET_URL>
# With authentication
python3 poc.py --target <TARGET_URL> --username <USER> --password <PASS>
⚠️ Warning: This PoC is for authorized security testing only. It uses detection-only techniques and does not exploit or damage target systems.
Test Lab¶
This repository includes a Docker-based test environment with both vulnerable and patched applications.
Quick Start¶
# Clone and navigate to CVE directory
cd CVE-2026-28470
# Start both applications
docker-compose up -d
# Run tests
./run-tests.sh # Linux/Mac
./run-tests.ps1 # Windows PowerShell
Application Endpoints¶
| Application | URL | Status |
|---|---|---|
| Vulnerable App | http://localhost:8080 | Shows vulnerability |
| Patched App | http://localhost:8081 | Demonstrates fix |
Directory Structure¶
├── README.md # English documentation
├── README_KO.md # Korean documentation
├── poc.py # PoC detection script
├── docker-compose.yml # Container orchestration
├── run-tests.sh # Linux/Mac test runner
├── run-tests.ps1 # Windows test runner
├── vulnerable-app/ # Vulnerable version
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
└── patched-app/ # Fixed version
├── app.py
├── Dockerfile
└── requirements.txt
References¶
- https://github.com/openclaw/openclaw/commit/d1ecb46076145deb188abcba8f0699709ea17198
- https://github.com/openclaw/openclaw/security/advisories/GHSA-3hcm-ggvf-rch5
- https://www.vulncheck.com/advisories/openclaw-exec-allowlist-bypass-via-command-substitution-in-double-quotes
Generated by PoC Generator on 2026-04-10T16:24:23.094188812
Detection and prevention¶
Ready-to-deploy defensive rules for CVE-2026-28470, for authorized testing and blue-team detection engineering:
- Snort IDS signature —
prevention/snort.rules - YARA detection rule —
prevention/yara.yar - Nginx mitigation —
prevention/nginx.conf - Apache HTTPD mitigation —
prevention/httpd.conf - Detection-only PoC —
poc.py - Rule notes —
prevention/README.md
References: NVD — CVE-2026-28470 · full write-up on the searchable site
Detection & prevention rules¶
alert tcp any any -> any any (msg:"CVE-2026-28470 OpenClaw RCE Command Injection via Dollar Parentheses"; flow:established,to_server; content:"OpenClaw"; nocase; content:"$("; distance:0; content:")"; distance:0; within:1000; classtype:attempted-admin; sid:1000000; rev:1; priority:1;)
alert tcp any any -> any any (msg:"CVE-2026-28470 OpenClaw RCE Command Injection via Backticks"; flow:established,to_server; content:"OpenClaw"; nocase; content:"`"; distance:0; content:"`"; distance:1; within:1000; classtype:attempted-admin; sid:1000001; rev:1; priority:1;)
alert tcp any any -> any any (msg:"CVE-2026-28470 OpenClaw RCE Command Substitution in Double Quotes"; flow:established,to_server; content:"OpenClaw"; nocase; content:"|22|"; content:"$("; distance:0; within:500; content:")|22|"; distance:0; within:500; classtype:attempted-admin; sid:1000002; rev:1; priority:1;)
alert tcp any any -> any any (msg:"CVE-2026-28470 OpenClaw RCE Backtick Substitution in Double Quotes"; flow:established,to_server; content:"OpenClaw"; nocase; content:"|22|"; content:"`"; distance:0; within:500; content:"`"; distance:1; within:500; content:"|22|"; distance:0; within:500; classtype:attempted-admin; sid:1000003; rev:1; priority:1;)
alert tcp any any -> any any (msg:"CVE-2026-28470 OpenClaw RCE Exec Approval Bypass Attempt"; flow:established,to_server; content:"exec"; nocase; content:"approval"; nocase; distance:0; within:100; pcre:"/(\$\([^)]+\)|`[^`]+`)/i"; classtype:attempted-admin; sid:1000004; rev:1; priority:1;)
rule CVE_2026_28470_OpenClaw_RCE_Command_Injection {
meta:
author = "Security Engineer"
description = "Detects OpenClaw RCE vulnerability CVE-2026-28470 command injection attempts"
cve = "CVE-2026-28470"
date = "2024-01-01"
severity = "high"
category = "exploit"
strings:
$cmd_subst_1 = "\"$(" ascii nocase
$cmd_subst_2 = "$()\"" ascii nocase
$cmd_subst_3 = "\"`" ascii nocase
$cmd_subst_4 = "`\"" ascii nocase
$pattern_1 = /"\$\([^)]*\)"/ ascii
$pattern_2 = /"`[^`]*`"/ ascii
$pattern_3 = /"[^"]*\$\([^)]*\)[^"]*"/ ascii
$pattern_4 = /"[^"]*`[^`]*`[^"]*"/ ascii
$openclaw_exec = "openclaw" ascii nocase
$exec_approval = "exec" ascii nocase
$allowlist = "allowlist" ascii nocase
$malicious_cmd_1 = "$(cat /etc/passwd)" ascii nocase
$malicious_cmd_2 = "$(whoami)" ascii nocase
$malicious_cmd_3 = "$(id)" ascii nocase
$malicious_cmd_4 = "`cat /etc/passwd`" ascii nocase
$malicious_cmd_5 = "`whoami`" ascii nocase
$malicious_cmd_6 = "$(wget" ascii nocase
$malicious_cmd_7 = "$(curl" ascii nocase
$malicious_cmd_8 = "`wget" ascii nocase
$malicious_cmd_9 = "`curl" ascii nocase
condition:
any of ($cmd_subst_*) or
any of ($pattern_*) or
(any of ($malicious_cmd_*) and ($openclaw_exec or $exec_approval))
}
rule CVE_2026_28470_OpenClaw_Exploit_Artifacts {
meta:
author = "Security Engineer"
description = "Detects exploitation artifacts for CVE-2026-28470 OpenClaw command injection"
cve = "CVE-2026-28470"
date = "2024-01-01"
severity = "high"
category = "artifact"
strings:
$hex_pattern_1 = { 22 24 28 } // "$( in hex
$hex_pattern_2 = { 29 22 } // )" in hex
$hex_pattern_3 = { 22 60 } // "` in hex
$hex_pattern_4 = { 60 22 } // `" in hex
$log_pattern_1 = "exec approval" ascii nocase
$log_pattern_2 = "allowlist bypass" ascii nocase
$log_pattern_3 = "command substitution" ascii nocase
$log_pattern_4 = "openclaw" ascii nocase
$exploit_string_1 = "\"$(echo" ascii nocase
$exploit_string_2 = "echo)\"" ascii nocase
$exploit_string_3 = "\"`echo" ascii nocase
$exploit_string_4 = "echo`\"" ascii nocase
$exploit_string_5 = "\"$(ls" ascii nocase
$exploit_string_6 = "\"$(ps" ascii nocase
condition:
(any of ($hex_pattern_*) and any of ($log_pattern_*)) or
any of ($exploit_string_*)
}
rule CVE_2026_28470_OpenClaw_Memory_Indicators {
meta:
author = "Security Engineer"
description = "Memory-based indicators for CVE-2026-28470 OpenClaw exploitation"
cve = "CVE-2026-28470"
date = "2024-01-01"
severity = "medium"
category = "memory"
strings:
$memory_1 = "openclaw.exe" ascii nocase
$memory_2 = "exec_approval" ascii nocase
$memory_3 = "allowlist_check" ascii nocase
$shell_exec_1 = "/bin/sh" ascii
$shell_exec_2 = "/bin/bash" ascii
$shell_exec_3 = "cmd.exe" ascii nocase
$shell_exec_4 = "powershell" ascii nocase
$injection_marker_1 = { 24 28 [1-50] 29 } // $(...) pattern
$injection_marker_2 = { 60 [1-50] 60 } // `...` pattern
condition:
any of ($memory_*) and
(any of ($shell_exec_*) or any of ($injection_marker_*))
}
# CVE-2026-28470: OpenClaw RCE Prevention Rules
# Block command substitution syntax in exec approvals bypass attempts
# Block requests containing command substitution patterns
location / {
# Block $() command substitution syntax
if ($request_uri ~* "\$\([^)]*\)") {
return 403;
}
# Block backtick command substitution
if ($request_uri ~* "`[^`]*`") {
return 403;
}
# Block encoded command substitution patterns
if ($request_uri ~* "(%24|%5C%24)\([^)]*\)") {
return 403;
}
# Block encoded backticks
if ($request_uri ~* "(%60|%5C%60)[^%60]*(%60|%5C%60)") {
return 403;
}
}
# Block command substitution in request body
location /api/ {
# Check request body for command substitution
lua_need_request_body on;
access_by_lua_block {
local body = ngx.var.request_body
if body then
# Check for $() patterns
if string.match(body, "%$%([^%)]*%)") then
ngx.status = 403
ngx.say("Blocked: Command substitution detected")
ngx.exit(403)
end
# Check for backtick patterns
if string.match(body, "`[^`]*`") then
ngx.status = 403
ngx.say("Blocked: Command substitution detected")
ngx.exit(403)
end
end
}
}
# Block suspicious headers that might contain command injection
location / {
# Block command substitution in User-Agent
if ($http_user_agent ~* "\$\([^)]*\)|`[^`]*`") {
return 403;
}
# Block command substitution in Referer
if ($http_referer ~* "\$\([^)]*\)|`[^`]*`") {
return 403;
}
# Block command substitution in custom headers
if ($http_x_forwarded_for ~* "\$\([^)]*\)|`[^`]*`") {
return 403;
}
}
# Specific protection for OpenClaw exec approval endpoints
location ~* ^/(exec|execute|approval|command)/ {
# Strict filtering for exec-related endpoints
if ($request_method !~ ^(GET|POST)$) {
return 405;
}
# Block any shell metacharacters
if ($request_uri ~* "[\$`;&|><\\\n\r]") {
return 403;
}
# Block double-quoted strings containing command substitution
if ($request_uri ~* "\"[^\"]*(\$\([^)]*\)|`[^`]*`)[^\"]*\"") {
return 403;
}
# Add security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
}
# Block query parameters with command substitution
map $args $block_args {
default 0;
"~*\$\([^)]*\)" 1;
"~*`[^`]*`" 1;
"~*(%24|%5C%24)\([^)]*\)" 1;
"~*(%60|%5C%60)[^%60]*(%60|%5C%60)" 1;
}
location / {
if ($block_args = 1) {
return 403;
}
}
# Rate limiting for exec-related endpoints
limit_req_zone $binary_remote_addr zone=exec_limit:10m rate=5r/m;
location ~* ^/(exec|execute|approval|command)/ {
limit_req zone=exec_limit burst=2 nodelay;
limit_req_status 429;
}
# ModSecurity rules for CVE-2026-28470 - OpenClaw RCE via command substitution bypass
# Protects against command injection through $() and backtick substitution in double-quoted strings
# Rule 1000000: Block command substitution with $() syntax
SecRule REQUEST_BODY "@detectSQLi" \
"id:1000000,\
phase:2,\
block,\
msg:'CVE-2026-28470: Command substitution attack detected - $() syntax',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:8,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
SecRule ARGS "@rx \$\([^)]*\)" \
"id:1000001,\
phase:2,\
block,\
msg:'CVE-2026-28470: Command substitution attack detected - $() in parameters',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:9,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000002: Block backtick command substitution
SecRule ARGS "@rx `[^`]*`" \
"id:1000002,\
phase:2,\
block,\
msg:'CVE-2026-28470: Backtick command substitution attack detected',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:9,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000003: Block command substitution in double-quoted strings
SecRule ARGS "@rx \"[^\"]*\$\([^)]*\)[^\"]*\"" \
"id:1000003,\
phase:2,\
block,\
msg:'CVE-2026-28470: Command substitution in double-quoted string detected',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:9,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000004: Block backtick substitution in double-quoted strings
SecRule ARGS "@rx \"[^\"]*`[^`]*`[^\"]*\"" \
"id:1000004,\
phase:2,\
block,\
msg:'CVE-2026-28470: Backtick substitution in double-quoted string detected',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:9,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000005: Block command substitution in request body
SecRule REQUEST_BODY "@rx \$\([^)]*\)" \
"id:1000005,\
phase:2,\
block,\
msg:'CVE-2026-28470: Command substitution attack in request body',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:8,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000006: Block backtick substitution in request body
SecRule REQUEST_BODY "@rx `[^`]*`" \
"id:1000006,\
phase:2,\
block,\
msg:'CVE-2026-28470: Backtick substitution attack in request body',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:8,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000007: Block command substitution in HTTP headers
SecRule REQUEST_HEADERS "@rx \$\([^)]*\)" \
"id:1000007,\
phase:1,\
block,\
msg:'CVE-2026-28470: Command substitution attack in HTTP headers',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:8,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
# Rule 1000008: Block backtick substitution in HTTP headers
SecRule REQUEST_HEADERS "@rx `[^`]*`" \
"id:1000008,\
phase:1,\
block,\
msg:'CVE-2026-28470: Backtick substitution attack in HTTP headers',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
severity:CRITICAL,\
tag:'attack-injection',\
tag:'CVE-2026-28470',\
tag:'OWASP_CRS',\
ver:'CVE-2026-28470/1.0',\
maturity:1,\
accuracy:8,\
t:none,\
ctl:auditLogParts=+E,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
Frequently asked questions¶
What is CVE-2026-28470?¶
CVE-2026-28470 is a Critical (9.8) vulnerability: OpenClaw versions prior to 2026.2.2 contain an exec approvals (must be enabled) allowlist…. This entry ships ready-to-deploy detection and prevention rules (Snort, YARA, Nginx, Apache, Sigma) plus a detection-only PoC and a Docker test lab.
How do I detect CVE-2026-28470?¶
Deploy the Snort and YARA detection rule included with this entry (see Detection & prevention rules below), then validate it against the detection-only PoC in the Docker test lab.
How do I block or mitigate CVE-2026-28470?¶
Apply the Nginx and Apache mitigation config included with this entry, and upgrade to a fixed version per the vendor advisory (see the NVD record for affected versions).
For authorized security testing and research only. See the full source and NVD record.