Nuclei Templates Explained — Building Custom Detection Rules
Published April 26, 2026 · 14 min read
Nuclei from ProjectDiscovery has eaten Nessus' lunch in the bug-bounty world. The nuclei-templates repo ships with 9,000+ community-maintained YAML rules covering CVEs, misconfigurations, exposed panels, and tech-stack fingerprints. The killer feature is that you can author your own templates — no SDK, no compiled binaries, just YAML — and run them at the same speed as the official ones. This guide walks the template DSL end-to-end.
Why Nuclei beats traditional scanners
Nessus and Qualys ship hard-coded plugins maintained by their vendor. If a CVE breaks tomorrow, you wait for an update. Nuclei templates are version-controlled YAML in a public repo — a CVE published at 09:00 UTC often has a Nuclei template in PR by 11:00 UTC. The Go-based engine handles thousands of concurrent HTTP requests with retries, rate limits, and resumable scans.
Template anatomy
Every Nuclei template has the same skeleton: id, info block, one or more requests (HTTP, network, file, headless, DNS, SSL, code, etc.), and matchers/extractors that determine when the rule fires.
id: example-tech-detect
info:
name: Example Tech Detection
author: axveil
severity: info
description: Fingerprints Example tech via response header.
reference:
- https://example.com/security-advisory
tags: tech,detect,example
http:
- method: GET
path:
- "{{BaseURL}}/"
matchers-condition: and
matchers:
- type: word
part: header
words:
- "X-Powered-By: ExampleTech"
case-insensitive: true
- type: status
status:
- 200
extractors:
- type: regex
part: header
regex:
- 'X-Powered-By: ExampleTech/([0-9.]+)'
group: 1Matchers — the firing logic
Six matcher types cover almost every detection: word, regex, binary, status, size, and dsl. Combine them with matchers-condition: and|or. The DSL matcher unlocks helpers like base64, md5, contains, regex, compare_versions, dns_resolve, and full Go templating expressions.
matchers:
- type: dsl
dsl:
- 'status_code == 200 && contains(body, "Spring")'
- 'compare_versions(extracted_version, "< 5.3.39")'
condition: andExtractors — pulling structured data
Extractors capture data from the response so it appears in your output and (importantly) becomes a variable in chained requests. Use internal: true for variables consumed by later steps but hidden from output.
extractors:
- type: kval
kval:
- server
- type: json
json:
- '.version'
internal: true
name: app_version
- type: xpath
xpath:
- '//meta[@name="generator"]/@content'Worked CVE example — CVE-2023-22515 (Confluence)
The 2023 Confluence Data Center privilege escalation is a perfect template study: unauthenticated POST to /setup/setupadministrator.actioncreates an admin user. Here's the detection:
id: CVE-2023-22515
info:
name: Confluence Server Broken Access Control
author: axveil
severity: critical
description: |
Improper access control in Confluence Server allows unauthenticated
creation of admin users via /setup/setupadministrator.action.
reference:
- https://nvd.nist.gov/vuln/detail/CVE-2023-22515
- https://confluence.atlassian.com/security/cve-2023-22515-1295682276.html
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 10.0
cwe-id: CWE-863
tags: cve,cve2023,confluence,atlassian,rce
http:
- raw:
- |
GET /setup/setupadministrator.action HTTP/1.1
Host: {{Hostname}}
X-Atlassian-Token: no-check
matchers-condition: and
matchers:
- type: word
part: body
words:
- "<title>Configure System</title>"
- "username"
condition: and
- type: status
status:
- 200Multi-request workflows
Chain multiple requests when a vulnerability needs auth or multi-step setup. Variables extracted from request 1 flow into request 2.
http:
- raw:
- |
POST /api/login HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"u":"admin","p":"admin"}
extractors:
- type: regex
name: token
internal: true
regex:
- '"token":"([^"]+)"'
group: 1
- raw:
- |
GET /api/users HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer {{token}}
matchers:
- type: status
status: [200]Performance & scale tuning
-c 50 -bs 200 -rl 300— concurrency, batch size, rate limit per second.-headless— uses Chromium for DOM/JS-heavy targets. Costly, scope carefully.-stats— prints throughput & ETA for long scans.-resume— pick up scan after interruption (writesresume.cfg).-jsonl -o out.jsonl— stream JSON for SIEM ingestion.
Validating templates before publish
# Lint syntax
nuclei -t my-template.yaml -validate
# Smoke test on safe target
nuclei -t my-template.yaml -u http://testphp.vulnweb.com -debug
# Compare with what registered template would produce
nuclei -t my-template.yaml -duc -dastWorkflows — chaining templates with logic
Workflows are templates of templates. They let you express conditional logic — "if WordPress is detected, then run the WordPress CVE bundle" — without each downstream template needing to re-fingerprint the target. The workflow file uses the same YAML structure but adds a workflows block with matchers and subtemplates /tags to dispatch.
id: wordpress-conditional
info:
name: WordPress conditional CVE sweep
author: axveil
description: Fingerprint WP, then fan out to version-relevant CVEs.
workflows:
- template: http/technologies/wordpress-detect.yaml
matchers:
- name: wordpress-detected
subtemplates:
- tags: wordpress,cve
- template: http/exposures/configs/wp-config-backup.yaml
- template: http/misconfiguration/wordpress/wordpress-debug-log.yamlWorkflows cut a 9,000-template scan to ~80 templates per host once the fingerprinting layer has decided what tech the target is actually running. On a Class-C-sized estate that is the difference between a four-hour scan and a forty-minute scan, with the same true-positive coverage.
Out-of-band & interactsh detection
Many vulnerabilities — SSRF, blind XXE, blind command injection, log4j-style JNDI, blind XSS — only confirm via an out-of-band callback. ProjectDiscovery's interactshships a server you can self-host (or use the public instance) plus first-class template syntax for consuming the callback signal. The {{interactsh-url}} placeholder in a request body becomes a unique callback domain; matchers fire when the corresponding DNS, HTTP, or SMTP probe is seen at the interactsh server.
http:
- method: POST
path:
- "{{BaseURL}}/api/render"
body: |
{"url": "http://{{interactsh-url}}/probe"}
matchers:
- type: word
part: interactsh_protocol
words:
- "dns"
- "http"
condition: orFor air-gapped or regulated environments self-host interactsh on a separate domain you control with wildcard DNS, otherwise findings will leak external interaction back to ProjectDiscovery's shared infrastructure — a non-starter for a regulated bank or a defence prime.
Authoring discipline — what to test before you ship
- Use
severityconsistently — info, low, medium, high, critical. Reserve critical for unauthenticated remote code execution. - Always include a
referenceURL — preferably the vendor advisory and an NVD entry. - Add
classificationwith CVSS vector and CWE — downstream tooling depends on it. - Tag aggressively —
cve,cve2025,confluence,atlassian,rce— so users can filter scans cleanly. - Pin a
fingerprintsblock where you know the affected vendor / product so the template skips off-target hosts. - Add a
remediationfield describing the fix — patch version or config change.
The community template repositoryuses these same standards in CI; PRs that miss them get rejected. Your private templates should inherit the discipline so they remain readable a year later.
Where AxVeil fits
AxVeil runs the genuine Nuclei engine — not a re-implementation — wrapped in scheduled VAPT pipelines. We auto-update templates hourly, deduplicate findings across scans, and triage by exploit availability. Your custom YAML rules drop into a private template registry and run alongside the public ones.
Further reading
- OWASP Top 10 2026 Checklist — the categories your Nuclei sweep should map findings to.
- Burp Suite Tutorial 2026 — manual confirmation for the leads Nuclei surfaces.
- AWS Pentest Checklist 2026 — cloud exposures the misconfiguration templates catch.
- CVSS 3.1 vs 4.0 — scoring the CVEs your templates fire on.
Run Nuclei at scale with AxVeil.
Real Nuclei. 9,000+ templates. Custom YAML supported.
Talk to us about scoping →