1. Running Threat Detection (--detect)

Enable the security detection engine using the --detect / -d flag:

caddy-analyze --detect /var/log/caddy/access.log

Per-IP Suspicious Request Details

The security report shows the actual suspicious requests per offending IP, including detection type, description, HTTP method, and path:

  - 192.168.1.100     15 malicious requests
        [sql_injection] SQL injection attempt GET /search?id=1' OR '1'='1
        [scanner] Scanner / automated tool detected GET /admin

This information is available in all output formats (table, JSON, CSV, HTML).

2. URL Unescaping & Evasion Prevention

Before evaluating detection rules, caddy-analyze automatically unescapes URL percent-encodings (e.g., converting %2e%2e%2f to ../ and %3Cscript%3E to <script>) to prevent attackers from bypassing security rules using URL encoding tricks. Additionally, a second pass matches against the raw (non-unescaped) URI to catch multibyte-encoded traversal sequences (%c0%ae%c0%ae%c0%af, %252e%252e%252f) and internal host probe attempts that would be lost after unescaping.

Memory Bounding

The detection engine bounds memory usage on huge logs via two mechanisms:

3. Threat Rule Specification (26 Categories)

Every detection carries a confidence score (1โ€“10) based on pattern specificity, and MITRE ATT&CK technique IDs for SOC mapping. The engine ships 171 signature patterns across the 26 categories below. The patterns listed under each card are representative examples โ€” each card also shows the real number of signatures it contains (e.g. SQL injection matches 19 distinct rule families, from UNION SELECT and comment-bypass to time-based blind and out-of-band exfiltration).

SQL Injection

UNION SELECT, OR 1=1, pg_sleep, INTO OUTFILE, @@version, etc.

19 signatures

T1190 conf 6โ€“10

NoSQL Injection

$ne, $gt, $regex, $where, $nin, %24ne, etc.

3 signatures

T1190 conf 7โ€“8

XSS

<script, onerror=, onfocus=, alert(, document.cookie, data:text/html, etc.

18 signatures

T1059.007 T1189 conf 2โ€“9

SSTI

__class__, __mro__, freemarker, nunjucks, {{7*7}}, os.popen, <#assign, <%=, __${...}__, etc.

6 signatures

T1190 conf 8โ€“9

SSRF

169.254.169.254, 0x7f000001, gopher://, dict://, redis://, etc.

11 signatures

T1190 conf 6โ€“10

RCE

/bin/sh, whoami, /dev/tcp/, powershell, certutil, eval(), rO0AB, _$$ND_FUNC$$_, etc.

23 signatures

T1059 T1190 conf 7โ€“10

Path Traversal / LFI

../, ..%00, /etc/passwd, /proc/self/*, php://input, etc.

10 signatures

T1083 conf 6โ€“9

GraphQL Introspection

__schema, __type, IntrospectionQuery, etc.

3 signatures

T1595.002 conf 6โ€“8

Log4j / JNDI

${jndi:ldap://, ${env:, ${lower:jndi, ${::-j}, etc.

4 signatures

T1190 T1059 conf 5โ€“10

XXE / XInclude

<!ENTITY, SYSTEM, PUBLIC, xi:include, xpointer, etc.

6 signatures

T1190 conf 8โ€“9

Open Redirect

?url=http://, ?redirect=//, //evil.com, ?url=/\, etc.

5 signatures

T1566.002 conf 7

LDAP Injection

(&(, (|(, )(|(, URL-encoded operators, etc.

2 signatures

T1190 conf 7โ€“8

XPath Injection

]|//*, .//*, etc.

2 signatures

T1190 conf 7

CRLF / Log Injection

%0d%0aSet-Cookie:, %0d%0aLocation:, literal CRLF, %E5%98%8A%E5%98%8D, etc.

4 signatures

T1190 T1059 conf 5โ€“8

Prototype Pollution

__proto__, constructor.prototype, JSON payloads, etc.

2 signatures

T1190 T1059.007 conf 7โ€“8

SSI Injection

<!--#exec cmd=, #include virtual=, #echo var=, etc.

3 signatures

T1190 T1059 conf 7โ€“9

User-Agent Rotation

Behavioral heuristic โ€” IPs rotating โ‰ฅ10 distinct UAs (credential stuffing, evasive scanners), etc.

behavioral heuristic

T1595.001 conf 6 ยท behavioral

JWT Abuse

"alg":"none" bypass, JWT token in URI, kid path traversal, Bearer token leak, etc.

7 signatures

T1550.001 T1190 conf 4โ€“10

Object Enumeration (BOLA/IDOR)

Sequential ID enumeration per path template (โ‰ฅ10 distinct IDs on /api/users/{id}), etc.

behavioral heuristic

T1595.002 T1190 conf 7 ยท behavioral

Beaconing / C2

Periodic callback detection (inter-arrival CV < 0.25, 10โ€“50 samples per path), etc.

behavioral heuristic

T1071.001 T1573 conf 6 ยท behavioral

LFI Wrapper Abuse

phar://, data://, expect://, compress.zlib, etc.

2 signatures

T1083 T1190 conf 8โ€“9

Sensitive File Probes

.env, .git/config, id_rsa, dump.sql, phpinfo.php, etc.

17 signatures

T1083 T1552.001 conf 4โ€“9

Admin Probes

/phpmyadmin, /actuator/*, /h2-console, /swagger-ui, etc.

13 signatures

T1595.002 conf 5โ€“9

WordPress Probes

/wp-content/plugins/, /xmlrpc.php, /wp-json/wp/v2/, etc.

8 signatures

T1595.002 conf 6โ€“8

CGI Probes

/cgi-bin/, .cgi, .fcgi, etc.

2 signatures

T1595.002 conf 5โ€“7

Scanner Tools

sqlmap, nuclei, gobuster, ffuf, wpscan, masscan, hydra, metasploit, shodan, etc.

1 rule ยท 73 tools

T1595 conf 9

4. Real-time Firewall Guard Daemon (guard)

The guard subcommand monitors log streams and automatically adds offending IPs to Linux iptables DROP rules when attack thresholds are exceeded:

โš‘ Root required

guard requires root/sudo because it modifies iptables rules. Run with sudo or as root, or integrate as a systemd service.
sudo caddy-analyze guard --limit 50 --window 1m docker://my-caddy

Audit Logging

Use --audit-log <path> to record every block and unblock action as a JSON-lines file. Each entry includes timestamp, action, IP, reason, ban duration, and the user who ran the command. The file is created with 0600 permissions. Available on guard, block, and unban subcommands.

sudo caddy-analyze guard --audit-log /var/log/caddy-analyzer/audit.jsonl docker://my-caddy
# Example entry:
{"ts":"2025-01-15T14:29:01Z","action":"block","ip":"203.0.113.5","reason":"12 malicious request(s)","duration":"24h0m0s","user":"root"}
# Other reasons you may see: " auth failures", " not found", " requests",
# " requests from  (distributed scan)", "cred_stuffing", "threat_intel:  score= (...)"

State Persistence

Use --state-file <path> to persist blocked-IP state across guard restarts. When the guard daemon restarts, it reloads previously blocked IPs, cleans up expired bans, and resumes enforcement. Without this flag, all bans are lost on restart. The block and unban commands also accept --state-file to sync manual blocks/unbans with the guard's persisted state.

sudo caddy-analyze guard --state-file /var/lib/caddy-analyzer/blocked.json docker://my-caddy
sudo caddy-analyze block --state-file /var/lib/caddy-analyzer/blocked.json 203.0.113.5
sudo caddy-analyze unban --state-file /var/lib/caddy-analyzer/blocked.json 203.0.113.5

IP Allowlist (Never Block)

Use --never-block to specify IPs/CIDRs that should never be banned, protecting trusted gateways, proxies, or health-check IPs from false-positive blocks. Use --never-block-file to load a larger allowlist from a file (one IP/CIDR per line, # comments supported). The two flags can be combined โ€” entries are merged.

sudo caddy-analyze guard \
  --never-block 10.0.0.0/8,192.168.1.1 \
  --never-block-file /etc/caddy-analyzer/allowlist.txt \
  docker://my-caddy

Pattern-Detection Blocking

Besides rate and status thresholds, guard also blocks IPs whose requests match security patterns (SQLi, XSS, RCE, etc.). Use --detect-confidence <1-10> to set the minimum confidence score required to trigger a block (default 8); detections below the threshold are reported in the audit log but not blocked. Pass 0 to disable pattern-based blocking entirely:

โš  Danger

Setting --detect-confidence 0 disables all pattern-based blocking. Only rate and status thresholds will trigger blocks. SQLi, XSS, RCE, and Log4j attacks will pass through unblocked if they don't exceed rate limits.
sudo caddy-analyze guard --detect-confidence 8 docker://my-caddy
# Block only very high-signal attacks (UNION SELECT, ${jndi:...})...
sudo caddy-analyze guard --detect-confidence 9 docker://my-caddy
# Disable pattern-based blocking (rate/status thresholds only)...
sudo caddy-analyze guard --detect-confidence 0 docker://my-caddy

Confidence Scoring

Every detection is assigned a confidence score from 1 (low) to 10 (high) based on the specificity and reliability of the matched pattern. High-confidence patterns (e.g. UNION SELECT, ${jndi:ldap://) score 9โ€“10, while broad or ambiguous patterns (e.g. onerror= which can appear in legitimate payloads) score 3โ€“5. This allows downstream consumers to filter noise and prioritize high-signal detections.

5. MITRE ATT&CK Tags

Every detection carries MITRE ATT&CK technique IDs (e.g. T1190 for Exploit Public-Facing Application, T1595 for Active Scanning). This lets SOC analysts build ATT&CK Navigator coverage layers from caddy-analyzer output and map detections to adversary techniques. Tags are included in JSON output and Sigma rules.

6. Sigma Rule Export

Export 23 detection categories as Sigma YAML rules for SIEM import (Splunk, Elastic, Sigma-compatible SIEMs). Rules include MITRE ATT&CK tags, deterministic UUIDs, and dynamically-constructed detection conditions. Validate with sigma check.

โ„น Note

The 3 behavioral detections (ua_rotation, object_enumeration, beaconing) are not pattern-based and are not exported as Sigma rules. They require temporal analysis across multiple requests and cannot be expressed as static patterns.
caddy-analyze export-sigma                    # stdout
caddy-analyze export-sigma rules.yml          # file
caddy-analyze export-sigma - | sigma check    # pipe to validator

7. IOC Defanging (--defang)

Use --defang to defang IPs and URLs in all output formats for safe sharing of reports containing IOCs. IPs are defanged (192.168.1.1 โ†’ 192[.]168[.]1[.]1) and URL schemes are defanged (http:// โ†’ hxxp://, https:// โ†’ hxxps://). Works across all commands: report, detect, top, tail, diff, and log listing mode.

caddy-analyze --detect --defang access.log
caddy-analyze top ip --defang access.log
caddy-analyze tail --defang access.log