Hi everyone,
I’ve been building a Suricata based detection and response tool specifically targeting the threats going after the OpenClaw AI agent ecosystem. Since it’s built entirely on Suricata and I’ve spent significant time on rule engineering, I wanted to share it here and get feedback from people who know the engine deeply.
Why this exists
Between January and March 2026, the OpenClaw ecosystem faced a concentrated wave of attacks:
- ClawHavoc campaign — 1,184+ malicious skills distributed via ClawHub, delivering AMOS, Vidar, and GhostSocks infostealers
- GhostClaw/GhostLoader RAT — distributed through typosquatted npm packages (
@openclaw-ai/openclawai), exfiltrating data to GoFile.io via trackpipe.dev C2 (source: JFrog Security Research) - AMOS Stealer — macOS-focused infostealer harvesting
openclaw.json, API keys, crypto wallets, and SSH credentials - 135,000+ exposed instances found on the public internet, many with zero authentication
- 25 CVEs affecting OpenClaw components, up to CVSS 9.9 (sandbox escape, pre-auth RCE, command injection)
Existing rulesets (ET Open, ET Pro) don’t cover these because the attack surface is specific to AI agent ecosystems MCP protocol exploitation, WebSocket gateway attacks, AI skill supply chain poisoning, prompt injection delivery, etc. I couldn’t find Suricata rules covering any of these, so I built a dedicated ruleset.
What CGTI Lite is
646 active Suricata rules (662 total, 16 disabled by default) across 13 specialized rule files, plus a Python-based management tool. The rules work standalone with any Suricata installation the management tool is optional.
SID range: 9200001–9204419 no conflicts with ET, Stamus, or other community rulesets.
Rule categories
| # | File | Active | Coverage |
|---|---|---|---|
| 01 | oc-infostealer-c2.rules |
67 | AMOS, Vidar, GhostClaw, GhostSocks, DigitStealer TLS C2, HTTP beacons, JA3 fingerprints |
| 02 | oc-reverse-shell.rules |
59 | Bash, netcat, Python, Node.js, PowerShell, Go, Java reverse shells |
| 03 | oc-websocket-attack.rules |
43 | CVE-2026-25253 full kill-chain (5 phases), ClawJacked, WS log poisoning |
| 04 | oc-malicious-skill-download.rules |
50 | Malicious skill installs, typosquatting, supply-chain indicators |
| 05 | oc-data-exfiltration.rules |
57 | Exfil to Telegram Bot API, Discord webhooks, Slack, cloud storage, paste sites |
| 06 | oc-gateway-exposure.rules |
42 | Exposed gateway detection, scanner fingerprinting, lateral movement |
| 07 | oc-cryptostealer-activity.rules |
41 | Wallet theft, mining, seed phrase exfil, exchange API key theft |
| 08 | oc-mcp-security.rules |
24 | MCP endpoint SSRF, tool injection, credential exfil via MCP channels |
| 09 | oc-exploit-cve.rules |
37 | CVE-specific exploit signatures (base set) |
| 10 | oc-exploit-detection.rules |
89 | Extended CVE coverage 25 CVEs with full kill-chain detection |
| 11 | oc-threat-intel-ioc.rules |
83 | Threat intel IOCs, malicious publishers, supply-chain indicators |
| 12 | oc-dns-threat-detection.rules |
34 | DNS C2, DNS rebinding, typosquatting domains, mDNS recon |
| 13 | oc-tls-certificate-anomaly.rules |
20 | TLS MITM, TOFU attacks, JA3/JARM, self-signed cert anomalies |
Rule design principles
I tried to follow what I’ve seen from high-quality Suricata rulesets. Feedback on whether I’m doing this right is genuinely welcome:
Dual indicator minimum: Every rule requires at least two independent content matches. No rules fire on a single content: string alone. For example, the AMOS Stealer TLS detection combines tls.sni with a specific IP range (91.92.242.0/24), not just one or the other.
Three confidence layers:
- Layer 1 (priority 1): Known C2 IPs/domains, CVE exploit signatures, JA3/JARM fingerprints near-zero FP
- Layer 2 (priority 2): Behavioral patterns, protocol anomalies, threshold-based detection
- Layer 3 (priority 3): Heuristics, scanner detection, broad pattern matching
MITRE ATT&CK metadata on every rule:
metadata:malware_family GhostClaw, mitre_attack T1071.001,
signature_severity Critical, false_positive Zero,
created_at 2026_03_17;
Standard variables only: All rules use $HOME_NET, $EXTERNAL_NET, and $DNS_SERVERS no custom variables needed. Works with default suricata.yaml out of the box.
Tested on Suricata 6.0+ through 8.0.4.
False positive methodology
16 rules are disabled by default. Each has a # DISABLED-FP: comment explaining exactly why it fires on legitimate traffic and under what conditions it’s safe to re-enable. Some examples:
SID:9200872— Python REPL detection disabled because REPL is a core OpenClaw featureSID:9202610—tools/call + execmatches legitimate MCP tools likeexecute_querySID:9201070—registry.npmjs.orgDNS query fires on everynpm install
All active rules were tested against common OpenClaw usage patterns: Discord/Slack integrations, Telegram Bot API, MCP filesystem tools, crypto trading bots, npm workflows. The README has a full tuning guide per use case.
Management tool
The rules are the core deliverable and work with any Suricata deployment. But the project also includes a cross-platform management tool (cgti_lite.py, single file, rich as the only dependency) that wraps Suricata with some useful automation:
IDS + IPS modes:
- IDS: standard
af-packetmonitoring - IPS on Linux: automatic
iptablesNFQUEUE setup, in placealert→droprule conversion (reverts on stop),nfq:section auto configured insuricata.yaml. Usessubprocess.Popenwithos.setpgrpinstead of Suricata’s-Dflag to avoid the fork race condition with NFQ binding.
Enhanced Autoblock (DNS aware IP blocking):
This is the feature I’m most interested in getting feedback on. When monitoring eve.json in real-time, the autoblock system:
- Reads each alert from EVE
- For non DNS alerts: blocks source IP (inbound threats) and destination IP (outbound C2/exfil) via OS native firewall
iptables -Ion Linux,pfctltable on macOS,netsh advfirewallon Windows - For DNS alerts: the destination IP is the DNS server (private IP should never be blocked). Instead, it extracts the queried domain from the alert signature, resolves it via system DNS to get the real IP(s), and blocks those resolved IPs. This way, a DNS alert for
trackpipe.devresults in blocking the actual C2 server IP, not your DNS resolver. - Severity filtering: configurable threshold (default: block severity 1-3, skip severity 4)
- Private IP protection: RFC1918, CGNAT, loopback, multicast, link-local addresses are never auto blocked
- Auto whitelists configured DNS servers from
suricata.dns_serversconfig - Bidirectional: every block creates both INPUT and OUTPUT firewall rules
Boot time autostart:
- Linux: systemd unit (
Type=oneshot+RemainAfterExit=yes). Handles the case where Ubuntu’s nativesuricata.servicestarts Suricata in IDS mode before CGTI runs — if IPS is configured, CGTI stops the IDS instance and restarts in NFQUEUE mode with full IPS setup. - macOS: launchd LaunchDaemon plist
- Windows: Task Scheduler with VBS silent launcher (no console flash)
Interface is read from config at runtime, not baked into service files.
Other features: Live EVE monitoring with color-coded severity, rule enable/disable/reload by SID, IP block management with reason logging, log rotation detection, automatic Suricata installation wizard.
Example rules
GhostClaw RAT TLS C2:
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;
)
CVE-2026-25253 gatewayUrl token exfiltration (phase 1 of 5-phase kill-chain):
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;
metadata:mitre_attack T1528, cve CVE-2026-25253,
signature_severity Critical, false_positive Low;
)
DNS C2 detection (triggers Enhanced Autoblock domain resolution):
alert dns $HOME_NET any -> any 53 (
msg:"OPENCLAW DNS GhostClaw C2 - trackpipe.dev";
dns.query; content:"trackpipe.dev"; nocase;
fast_pattern; isdataat:!1,relative;
classtype:trojan-activity; priority:1;
reference:url,research.jfrog.com/post/ghostclaw-unmasked/;
sid:9203942; rev:1;
metadata:malware_family GhostClaw, category ghostclaw-c2;
)
Threat intelligence sources
All rules are built from published research not generated or guessed:
- JFrog Security Research — GhostClaw/GhostLoader campaign
- Huntress — AMOS Stealer analysis, GhostSocks/OpenClaw 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 — exposed MCP servers, 135K+ instance scanning
- Hunt io — certificate analysis of 17,470+ exposed instances
- abuse ch SSLBL — JA3 fingerprint database
- MITRE ATT&CK — technique classification
Full attribution with reference URLs in every rule.
Links
- License: AGPL-3.0
- Rules only (no tool needed):
rules/directory drop into any Suricatarule-files:config - Github: GitHub - Senturkselim/CGTI-for-OpenClaw: Purpose built Suricata IDS/IPS management tool for OpenClaw AI agent community 646 detection rules, cross platform · GitHub
I’d genuinely appreciate feedback on rule quality, structure, Suricata best practices I might be missing, or anything that could be improved. FP reports from anyone running OpenClaw in production would also be very valuable.
Thanks for reading and thanks to the Suricata community and OISF team for building the engine that makes all of this possible.