|9 min read|Yvann Lièvre

Writing a Nuclei Template for a CVE: From Advisory to a Template That Fires (Without False Positives)

A CVE drops, the advisory is public, but no Nuclei template exists yet. Here is how to write a clean one: start from the fact, build the matchers, and above all prove it fires on a vulnerable target while staying silent on a patched one.

NucleiCVEDetectionVulnerability Scanning
Writing a Nuclei Template for a CVE: From Advisory to a Template That Fires (Without False Positives)

A critical CVE is published on a Friday evening. The advisory describes the flaw, the affected version, the vulnerable path. The question is no longer "am I affected?" but "how many of my assets are, right now?". Nuclei is the reference tool for answering that at scale: a fast engine, readable YAML templates, versioned like code. The catch is that when the CVE drops, the official template does not exist yet, it will arrive in a few days, sometimes a few weeks. That lag is your window of exposure.

Writing the template yourself closes that gap. But a badly written template is worse than none: it misses the vulnerable version (a false negative (you believe you are safe) or it fires on an already-patched one (a false positive) you drown the team in noise). This article shows how to write one that fires accurately, and above all how to prove it.

Why not just wait for the official template

Three reasons to know how to do it yourself:

  • The lag. Between a CVE's publication and a public template lies a variable delay. On an actively exploited flaw (an entry in the CISA KEV catalog), that delay is exactly the window in which attackers are scanning too.
  • Your in-house applications. No community project will ever cover your internal ERP, your custom portal, or that niche appliance. Detection on that perimeter is something nobody will write for you.
  • Prioritization. You cannot write a template for the year's 40,000 CVEs. Being able to do it fast for the handful that matter (the ones being exploited, exposed, on your critical assets) is a detection-engineering skill, not a luxury.

The anatomy of a Nuclei template

A template is a YAML file in two parts: the metadata (info) and the logic (the request plus the matchers). Here is the skeleton:

id: cve-2024-0000-config-disclosure
 
info:
  name: "ACME Portal < 4.2 - Unauthenticated Configuration Disclosure"
  author: your-team
  severity: high
  description: |
    ACME Portal before 4.2 exposes /api/v1/config without authentication,
    leaking database credentials and API keys.
  classification:
    cve-id: CVE-2024-0000
    cvss-score: 8.6
  tags: cve,cve2024,acme,exposure
 
http:
  - method: GET
    path:
      - "{{BaseURL}}/api/v1/config"
    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200
      - type: word
        part: body
        words:
          - '"db_password"'
          - '"api_key"'
        condition: and

(The example is illustrative: the principle matters more than the chosen CVE.) Each block has a role. The id is unique and descriptive. The info block carries the severity and the classification (the cve-id, the CVSS score), this is not decoration: it is what lets you triage, correlate and prioritize afterwards. The http section describes what you send and what proves the vulnerability.

Start from the fact, not the proof-of-concept

This is the most important point, and the most often skipped. On GitHub, an exploitation PoC almost always circulates before the template. The temptation is to copy it. Do not, for two reasons.

First, legal rigor: a PoC published with no explicit license is "all rights reserved" by default. Copying it into a template you share or resell is a problem. The fact described by the advisory, however ("version X exposes path Y which returns string Z") belongs to no one. A detection signature is your own work, just as an antivirus signature does not inherit the rights of the malware it detects.

Second, quality: a PoC aims to exploit, a template aims to observe safely. You do not want to drop a webshell to prove an RCE; you want the lightest, most reliable sign that the flaw is present. The advisory gives you exactly that sign: the path, the version marker, the response signature. That is your raw material.

Building the matchers, from coarse to precise

A matcher that returns "vulnerable" too easily is the number-one trap. Consider three levels:

Level 1: the status code alone. status: 200 on /api/v1/config. Insufficient: a patched version may still return 200 with an empty page or an error message. A status does not prove the vulnerability, it proves the path exists.

Level 2: status plus a keyword. Add the presence of "db_password" in the body. Much better: you only fire if the response actually contains the leaked data. The matchers-condition: and requires both conditions to be true.

Level 3: version discrimination. The subtle case. If version 4.2 (fixed) still returns the key but empty, Level 2 produces a false positive. You then need a regex matcher that captures a non-empty value, or read the version marker from a header. This is where the difference is decided between a template that makes noise and one your team trusts.

For a blind flaw (no directly observable response, an out-of-band injection, an SSRF), Nuclei provides interactsh: the template triggers a network callback to a control server and confirms the vulnerability through that callback, without ever exploiting the target.

Validating is not enough: you have to prove

Nuclei ships a built-in check:

nuclei -validate -t cve-2024-0000-config-disclosure.yaml

Beware the misunderstanding: -validate checks the syntax, not the effectiveness. A perfectly valid template can detect nothing, or everything. Syntactic validation is necessary, never sufficient.

The real proof is empirical, and it comes down to two tests:

  1. Does the template fire on a vulnerable target? Stand up the application in its vulnerable version (a Docker container of the right version does the job nicely) and run the template against it. If it does not fire, it is useless.
  2. Does it stay silent on a patched target? Stand up the fixed version and run again. If it still fires, you have a false positive, the worst outcome, because it erodes trust in all your alerts.

A template that has passed both tests is worth infinitely more than one that is merely "valid." That is the difference between "it compiles" and "it works, proven."

The traps that cost you

  • The over-generic matcher. Firing on a version banner ("Server: ACME/4.1") is fragile: banners get masked, removed, or linger after a back-ported fix. Always prefer the observable vulnerable behavior over the software's self-declaration.
  • The forgotten patched version. The "patched" test is not optional. Half of all false positives come from skipping it.
  • The duplicate. Before keeping your template, check that an upstream equivalent does not already exist. The cent tool aggregates and deduplicates template collections, useful so you do not maintain in duplicate what the community already covers.
  • Sloppy classifications. Fill in cve-id, cvss-score, severity. That is what makes your results usable, sortable by severity, correlatable with your other sources.

Prioritize: not all CVEs are equal

Writing a template has a cost. Spending it on the right flaws changes everything. Two free, public sources direct the effort:

  • CISA KEV (Known Exploited Vulnerabilities): the catalog of actively exploited flaws. A CVE on that list is an emergency, not a hypothesis.
  • EPSS (Exploit Prediction Scoring System): a 30-day exploitation probability. Useful for arbitrating between two flaws before either is exploited.

Crossing "this CVE is in KEV" with "it hits an exposed asset of mine" yields a short, actionable list: those are the templates to write first.

In summary

Writing a good Nuclei template for a CVE is a method, not improvisation: start from the fact in the advisory (not the PoC), build the most precise matcher possible (not just a status), and prove empirically that it fires on the vulnerable version and stays silent on the patched one. The rest (syntactic validation, classifications, deduplication) is hygiene.

That is precisely the discipline we apply at scale in the ThreatClaw Nuclei feed: every template is validated on the real engine, prioritized by KEV and EPSS, and shipped as a rapid response on the flaws that matter. When a critical CVE drops on a Friday evening, the window of exposure is already covered, you do not have to write it yourself under pressure.

Related articles