# Building 646 Suricata Rules to Detect AI Agent Threats: OpenClaw Security with CGTI Lite
Between January and March 2026, the OpenClaw AI agent ecosystem faced a wave of targeted attacks that existing security tools weren't equipped to handle. The ClawHavoc campaign distributed 1,184+ malicious skills through ClawHub. GhostClaw RAT spread via typosquatted npm packages. AMOS Stealer harvested macOS credentials. 135,000+ OpenClaw instances were found exposed on the public internet with zero authentication. 25 CVEs were disclosed, with CVSS scores reaching 9.9.
I looked for Suricata rules covering these threats. MCP protocol exploitation, WebSocket gateway attacks, AI skill supply-chain poisoning — none of it was covered by ET Open, ET Pro, or any community ruleset I could find.
So I built CGTI Lite for OpenClaw — 646 hand-crafted Suricata detection rules across 13 specialized categories, plus a cross-platform management tool. This post explains the detection engineering behind it.
GitHub: https://github.com/Senturkselim/CGTI-for-OpenClaw
The Threat Landscape
Here's what CGTI Lite detects, mapped to the actual campaigns:
| Threat | What It Does | CGTI Detection Method |
|---|---|---|
| ClawHavoc | 1,184+ malicious ClawHub skills distributing infostealers | C2 IPs, domains, skill download patterns, DNS queries |
| GhostClaw/GhostLoader | RAT via typosquatted npm packages, exfil to GoFile.io | TLS/HTTP C2 to trackpipe.dev, bootstrap payload URI, npm package detection |
| AMOS Stealer | macOS infostealer targeting openclaw.json, crypto wallets | TLS C2 (91.92.242.0/24), HTTP exfil patterns, BuildID header |
| Vidar 2.0 | Credential store theft from ~/.openclaw/ | JA3 fingerprint, TLS cert anomalies |
| GhostSocks | Proxy malware turning hosts into SOCKS proxies | Default cert CN, Stealth Packer indicators |
| 25 CVEs | RCE, sandbox escape, command injection | Full kill-chain signatures per CVE |
Rule Design: Why Two Indicators Minimum
Every CGTI rule requires at least two independent content matches. No rule fires on a single content: string alone. Here's why — and how it looks in practice.
Bad rule (single indicator, high FP risk):
alert http any any -> any any (
msg:"Suspicious download";
content:"download"; http.uri;
sid:9999999; rev:1;
)
This fires on literally any HTTP request with "download" in the URI.
CGTI approach (dual indicator):
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"CGTI-OC GHOSTCLAW - TLS Connection to trackpipe.dev C2 Panel";
flow:to_server,established;
tls.sni; content:"trackpipe.dev"; nocase; isdataat:!1,relative;
classtype:trojan-activity; priority:1;
reference:url,research.jfrog.com/post/ghostclaw-unmasked/;
sid:9200124; rev:1;
metadata:malware_family GhostClaw, mitre_attack T1071.001,
signature_severity Critical, false_positive Zero;
)
This combines tls.sni match + isdataat:!1,relative (exact domain, not substring) + flow:to_server,established (only outbound TLS handshakes). The false positive rate on a known C2 domain is effectively zero.
Three Confidence Layers
Rules are organized into detection confidence tiers:
Layer 1 — High Confidence (priority 1): Known C2 IPs and domains, CVE-specific exploit signatures, JA3/JARM fingerprints. These are indicators derived directly from published threat research (JFrog, Huntress, DepthFirst Security, etc.). Near-zero false positive rate.
Layer 2 — Medium Confidence (priority 2): Behavioral patterns like data exfiltration to paste sites, unusual WebSocket commands, HTTP requests matching supply-chain attack patterns. These use threshold-based detection and require protocol-specific scoping.
Layer 3 — Low Confidence (priority 3): Heuristic rules like scanner detection, broad IP geolocation lookups, generic curl-to-shell patterns. Informational — meant to be tuned per deployment.
Detecting a 5-Phase CVE Kill Chain
CVE-2026-25253 (CVSS 8.8) enables 1-click RCE through gatewayUrl token exfiltration. The attack has 5 distinct phases, and CGTI has detection rules for each:
Phase 1 — Token exfiltration via gatewayUrl:
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CGTI-OC CVE-2026-25253 Phase-1 gatewayUrl Token Exfil";
flow:established,to_server;
http.uri; content:"gatewayUrl=";
http.uri; content:"token="; distance:0;
classtype:trojan-activity; priority:1;
reference:cve,2026-25253;
sid:9200801; rev:1;
)
Detecting each phase individually means even if the attacker modifies one step, the other phases still trigger alerts. Defense in depth at the rule level.
The DNS Blocking Problem (And How I Solved It)
This is the most technically interesting part of the project.
When Suricata fires a DNS alert (e.g., "host queried trackpipe.dev"), the destination IP in the EVE log is your DNS resolver — typically 8.8.8.8 or 1.1.1.1. If your autoblock system naively blocks the destination IP from the alert, it blocks your DNS server. Your entire internet breaks.
CGTI's Enhanced Autoblock handles this differently:
- Detect that the alert is DNS traffic (port 53)
- Extract the queried domain from the alert signature text
- Resolve that domain via system DNS to get the actual IP(s)
- Block the resolved IPs (the real C2 server), not the DNS resolver
- Apply RFC1918/CGNAT/loopback protection — never block private IPs
- Auto-whitelist configured DNS servers
So a DNS alert for trackpipe.dev results in blocking the actual GhostClaw C2 infrastructure IP, not your DNS resolver. Bidirectional — both INPUT and OUTPUT firewall rules are created.
False Positive Management
16 rules are shipped disabled by default. Each has a # DISABLED-FP: comment explaining exactly why:
- SID:9200872 — Python REPL detection. Disabled because REPL is a core OpenClaw feature. Re-enable if you don't use the Python REPL.
-
SID:9202610 — MCP
tools/call + exec. Matches legitimate tools likeexecute_query. Re-enable if you don't use any MCP tool with "exec" in its name. -
SID:9201070 —
registry.npmjs.orgDNS. Fires on everynpm install. Re-enable if your OpenClaw host never runs npm.
The README includes a full tuning guide organized by use case: Discord/Slack integrations, Telegram bots, crypto trading, MCP filesystem tools, etc.
IPS Mode on Linux: Avoiding the Fork Race
A technical detail that took significant debugging: Suricata's -D (daemon) flag causes a fork race condition with NFQUEUE binding on Linux. The forked child process tries to bind the NFQ queue before the parent fully exits, sometimes resulting in a failed bind.
CGTI's solution: start Suricata with subprocess.Popen + os.setpgrp instead of using -D. This keeps the process in the foreground from Python's perspective but fully detached from the parent process group. The NFQUEUE binding succeeds reliably.
The IPS flow:
- Stop any existing Suricata instance (including Ubuntu's
suricata.service) - Convert alert rules to drop rules in-place (reverts on stop)
- Auto-configure
nfq:section in suricata.yaml - Set up
iptables -INFQUEUE rules (with automatic rollback on failure) - Start Suricata with
-q 0via Popen
Boot-Time Autostart: The Ubuntu Edge Case
On Ubuntu, installing Suricata via apt also installs suricata.service, which is enabled by default. At boot:
-
suricata.servicestarts Suricata in IDS mode (--af-packet) -
cgti-lite.serviceruns — but Suricata is already running
If IPS mode is configured, CGTI detects this situation: Suricata is running but in IDS mode, not IPS. CGTI stops the IDS instance, then restarts Suricata in full NFQUEUE/IPS mode with iptables rules, drop rule conversion, and NFQ configuration.
This edge case took real-world testing on Ubuntu VMs to discover and fix properly.
Rule Coverage Summary
13 rule files, 646 active rules, SID range 9200001–9204419:
| Category | Rules | What It Catches |
|---|---|---|
| Infostealer C2 | 67 | AMOS, Vidar, GhostClaw, GhostSocks, DigitStealer |
| Reverse Shells | 59 | 7 languages: bash, netcat, Python, Node.js, PowerShell, Go, Java |
| WebSocket Attacks | 43 | CVE-2026-25253 kill-chain, ClawJacked, log poisoning |
| Malicious Skills | 50 | Typosquatting, supply-chain, malicious install patterns |
| Data Exfiltration | 57 | Telegram, Discord, Slack, paste sites, cloud storage |
| Gateway Exposure | 42 | Scanner detection, exposed instances, lateral movement |
| Cryptostealer | 41 | Wallet theft, mining, seed phrases, exchange API keys |
| MCP Security | 24 | SSRF, tool injection, credential exfil |
| CVE Signatures | 126 | 25 CVEs with full kill-chain coverage |
| Threat Intel IOCs | 83 | Malicious publishers, known attacker infrastructure |
| DNS Threats | 34 | C2, rebinding, typosquatting domains |
| TLS Anomalies | 20 | MITM, JA3/JARM, self-signed cert detection |
Threat Intelligence Sources
All rules are built from published research — not generated or guessed:
- JFrog Security Research — GhostClaw/GhostLoader RAT campaign
- Huntress — AMOS Stealer analysis, GhostSocks campaign
- DepthFirst Security — CVE-2026-25253 kill-chain discovery
- Koi Security — ClawHavoc campaign (1,184+ malicious skills)
- Darktrace, Trend Micro, Ontinue — Vidar/AMOS distribution research
- Bitsight TRACE — 135K+ exposed instance scanning
- Hunt.io — certificate analysis of 17,470+ instances
- abuse.ch SSLBL — JA3 fingerprint database
- MITRE ATT&CK — technique classification
Every rule includes reference: URLs pointing to the original research.
Getting Started
Rules only (any Suricata installation):
Copy the rules/ directory into your Suricata rules path and add them to rule-files: in suricata.yaml. Done.
Full management tool:
git clone https://github.com/Senturkselim/CGTI-for-OpenClaw.git
cd CGTI-for-OpenClaw
chmod +x install.sh && ./install.sh
cgti install
sudo cgti start
Works on Linux, macOS, and Windows. Single Python file, rich as the only dependency.
What's Next
This is the first community-facing release from the CloudGo Threat Intelligence (CGTI) project. The rules will be updated as new threats emerge and new CVEs are disclosed. FP reports and contributions are welcome.
If you're running OpenClaw in production and want to test the rules against your traffic, I'd genuinely appreciate hearing about detection quality and false positive rates.
GitHub: https://github.com/Senturkselim/CGTI-for-OpenClaw
License: AGPL-3.0 — free forever.
Top comments (0)