Add the CVE channel document

cve.json carries virtual patches: rules written against a named
vulnerability, published as data so that every edge node enforces them
within the hour instead of waiting for an engine release. Engine 3.0.47 and
later fetch it hourly.

It starts empty, which is a valid state and says "no virtual patches at the
moment" — the engine accepts an empty rulesets list as of 3.0.47, and
publishing one is also how the whole channel stands down.

Separate from rulesets.json rather than part of it: each has its own
build_datetime, so each is applied or skipped on its own, and a mistake in
one cannot take out the other. Publishing a patch should not mean
republishing a 357KB mirror of the Core Rule Set.

CVE-CHANNEL.md documents the format, the param_names target, how severity
becomes the anomaly score, and the two mistakes worth avoiding: publishing a
rule for a CVE the engine already patches in code (both fire and the scores
add), and forgetting that there is no backtest for a patch written in the
hours after a disclosure — which is why withdrawal is a first-class
operation here.

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-10-22 14:45:39 +01:00
1 parent d6ab346bd3
commit 6ca0cd5d20
2 files changed
+91

No files matched your search

+87
View File
@@ -0,0 +1,87 @@
# The CVE channel (`cve.json`)
This document carries virtual patches: rules written against a named
vulnerability, published as data so that every edge node enforces them within
the hour instead of waiting for an engine release.
It is deliberately a second document in this repository, not a second
repository and not part of `rulesets.json`. Each has its own `build_datetime`,
so each is skipped or applied on its own, and a mistake in one cannot take out
the other.
Engine 3.0.47 and later fetch it hourly from:
https://git.artica.center/Andre/edgeguard-owasp-feed/raw/branch/main/cve.json
## Publishing a patch
Add a rule to the single ruleset, bump `build_datetime`, commit, push. An
unchanged `build_datetime` means every node skips the document without reading
it, so the stamp is what makes a publish take effect.
```json
{
"build_datetime": "2026-10-22T13:00:00Z",
"rulesets": [{
"id": "edgeguard-cve",
"name": "EdgeGuard CVE Virtual Patches",
"version": "1",
"source": "edgeguard-cve",
"description": "Virtual patches for named vulnerabilities",
"enabled": true,
"priority": 1,
"rules": [{
"id": "CVE-2026-109618-01",
"name": "PHP upload-progress field present",
"pattern": "^php_session_upload_progress$",
"targets": ["param_names"],
"action": "block",
"severity": "critical",
"category": "cve",
"cve": "CVE-2026-109618, CVE-2026-109619",
"enabled": true,
"references": ["https://nvd.nist.gov/vuln/detail/CVE-2026-109618"]
}]
}]
}
```
`source` must be `edgeguard-cve`. That is the source the channel owns and the
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.
Publishing an empty `"rulesets": []` withdraws the lot.
## Targets
The usual ones (`uri`, `query`, `args`, `body`, `headers`, `user_agent`,
`cookies`, `filename`, `all`) plus:
- **`param_names`** — the pattern is run against each parameter NAME on its
own: query parameters, urlencoded body fields and multipart
`Content-Disposition` names. An anchored pattern therefore anchors to one
name, and a parameter whose *value* happens to be the string can never match.
This is the shape CVE-2026-109618 needed and the reason it could not be
written against `args`, where names and values arrive as one blob and
`?note=PHP_SESSION_UPLOAD_PROGRESS` would have been refused.
Write `param_names` patterns in lower case; both the original and the
lowercased spelling of each name are tried.
## Severity is the score
`critical` 5, `high` 4, `medium` 3, `low` 2, against a default anomaly
threshold of 5. A patch that should refuse on its own is `critical`; one that
should only contribute is `medium` or below. Nothing else sets the score.
## Two things to get right
**Do not publish a rule for a CVE the engine already patches in code.** Both
would fire on the same request, the anomaly score would be the sum, and the
event would report one attack as two rules.
`TestPublishedFeedDoesNotDuplicateACompiledRule` in the engine fails if this
document names a CVE that `ruleCVEReferences` already covers.
**A patch written in the hours after a disclosure is written against an
advisory, not against traffic.** There is no backtest. If one turns out to
refuse something real, the remedy is to withdraw it — which is why withdrawal
is a first-class operation here.
+4
View File
@@ -0,0 +1,4 @@
{
"build_datetime": "2026-10-22T13:00:00Z",
"rulesets": []
}