Document importing from a Nuclei template, and what the importer refuses

A CVE record describes a vulnerability, not a request, which is why this
channel is written by hand. A Nuclei template contains the request — path,
query, headers, body — because that is what it sends, so for thousands of CVEs
the shape a virtual patch needs is already written down.

What cannot come across is the template's matchers: they read the RESPONSE to
decide whether the target was actually vulnerable, and a WAF decides before a
response exists. So an imported rule is strictly weaker than the template it
came from — it recognises the attempt, not the exploitation. That is why they
land as action "log", which the engine now honours: observed, recorded as an
event, scoring nothing.

Also records what the importer skips rather than guesses: a CVE already
patched in compiled code, a request that is entirely template variables, a
literal under twelve characters, the site root. And what it corrects: one
leading path segment, because a template is written against a laboratory where
the application is mounted somewhere — /laravel52/vendor/phpunit/... would
have been published unable to match a real attack at /vendor/phpunit/...

Documentation only. cve.json is untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5fpE6Gu4W6JoFMXyb7t7r
This commit is contained in:
AndreandClaude Opus 5 committed 2026-11-04 02:34:54 +00:00
1 parent 1e0ad6cd7b
commit d8426a1d6c
1 file changed
+54
+54
View File
@@ -57,6 +57,60 @@ only one it may clear, which is also what makes a rule **withdrawable**: remove
it, bump the stamp, and it stops being enforced everywhere within the hour. it, bump the stamp, and it stops being enforced everywhere within the hour.
Publishing an empty `"rulesets": []` withdraws the lot. Publishing an empty `"rulesets": []` withdraws the lot.
## Importing from a Nuclei template
A CVE record describes a vulnerability, not a request, which is why this
channel is written by hand. A **Nuclei template** does contain the request —
path, query, headers, body — because that is what it sends. So for thousands of
CVEs the shape a virtual patch needs is already written down.
go run ./tools/nuclei-importer -cves CVE-2025-31161,CVE-2024-4577 \
-merge edgeguard-rules/cve.json > /tmp/next.json
cp /tmp/next.json edgeguard-rules/cve.json
bash tools/publish-cve-feed.sh --check
**Imported rules land as `action: "log"`, and that is not timidity.** A template
decides whether a target was actually vulnerable by reading the RESPONSE —
words in the body, the content type, the status. A WAF decides before a
response exists, so the imported rule is strictly weaker than the template it
came from: the template confirms exploitation, the rule only recognises the
attempt. Watch what it would have caught in your own traffic, then change
`log` to `block` deliberately, per rule.
Each imported rule carries an `origin` field saying a human did not write its
pattern and what it came from. Do not remove it — it is the difference between
a rule somebody reasoned about and one a converter guessed.
### What it refuses to do
It skips rather than guesses, and prints why:
- **A CVE the engine already patches in code.** Both rules would fire and the
scores would add. Five are patched today: the two PHP2Shell ones, Log4Shell
(two) and Spring4Shell.
- **A request with nothing literal in it.** Templates are full of
`{{BaseURL}}` and `{{string_1}}`; a pattern that is mostly `.*` matches
ordinary traffic.
- **A request whose longest literal is under twelve characters**, or is the
site root. A rule on `/` matches everything.
### What it corrects, and why you should check anyway
It strips one leading path segment when three remain, because a template is
written against a laboratory where the application is mounted somewhere: the
phpunit template requests `/laravel52/vendor/phpunit/...` and `laravel52` is
that lab's directory. Without stripping it the rule is published, enabled, and
unable to match a real attack at `/vendor/phpunit/...`.
It prefers a header value carrying an injection marker (`${jndi:`, `<%`, `$(`,
`../`) over a path, and ignores standard headers entirely whatever their value.
An earlier version preferred headers over everything and produced the pattern
`Content-Type: text/html` for a PHP RCE — a rule that says nothing about the
attack and something about every request.
None of that makes the output right. Read every pattern before publishing.
## Targets ## Targets
The usual ones (`uri`, `query`, `args`, `body`, `headers`, `user_agent`, The usual ones (`uri`, `query`, `args`, `body`, `headers`, `user_agent`,