How ekmire Turns NVD CVEs Into Live WAF Rules in 60 Seconds
WAFs run on stale rules. ekmire fetches NVD CVEs daily, generates signed detection rules via LLM, and hot-reloads every running proxy in 60 seconds — no restart.
Every WAF you have ever used ran on stale rules. Cloudflare's managed rule sets update on Cloudflare's schedule. Open-source WAFs need someone to write, test, and merge a PR. Even the best-maintained rulesets have a gap between when a CVE is published and when a rule exists to detect it.
ekmire takes a different approach. A Supabase Edge Function pulls the NVD daily at 02:00 UTC, a Groq LLM generates a candidate detection rule from the CVE description, an admin reviews and approves it, and the signed bundle ships to every connected proxy within 60 seconds. No container restart. No deployment pipeline. No manual push.
This post explains how the pipeline works, why Ed25519 signing matters, how crowd-sourced false positive feedback sharpens the bundle over time, and what 60-second hot-reload looks like at the Rust level.
The stale-rules problem is getting worse
Most WAF operators discover new CVEs the same way attackers do: security news, NVD notifications, vendor advisories. Then comes the human work — understand the vulnerability, write a detection pattern, test it against real traffic, deploy it. That process takes days in a well-run team. In a team focused on shipping product, it often takes never.
2026 made this significantly harder. In April, NIST announced a fundamental shift in how the NVD enriches vulnerability data. CVE disclosure volumes have roughly tripled over five years, and NIST is transitioning to a risk-based model where most CVEs will enter the ecosystem without CVSS metadata — the severity score that automated tooling relies on to prioritise which vulnerabilities to act on. Automated pipelines that filter on CVSS scores will miss an increasing share of real threats.
ekmire's threat feed is designed to work around this. The LLM step generates candidate rules from CVE descriptions, not from CVSS scores. If a CVE describes a SQL injection pattern in a specific library version, Groq generates a detection candidate based on the description — with or without CVSS enrichment.
How the NVD CVE pipeline works
The pipeline runs on a Supabase Edge Function at 02:00 UTC every day:
- Fetch. The Edge Function queries the NVD REST API v2.0 for CVEs published or modified in the last 24 hours, filtered by CWEs relevant to web application threats: injection, path traversal, XSS, insecure deserialization, and prompt injection patterns.
- Generate. Each CVE description is sent to Groq (Llama 3.3 70B) with a structured prompt: extract the vulnerability pattern, generate a detection rule candidate in ekmire's rule schema, assign a severity, explain the match logic.
- Stage. Generated candidates land in a
threat_candidatestable asstatus: pending_review. No candidate ever reaches a proxy without a human review step. - Review. An ekmire admin inspects the candidate: does the pattern match what the CVE describes? Is it specific enough to avoid false positives? Is the severity accurate? Approval promotes the candidate to the active rule bundle.
- Publish. The bundle is Ed25519-signed, version-bumped, and served to every connected proxy. Hot-reload picks it up within 60 seconds.
CVE published to NVD
→ 02:00 UTC fetch (Edge Function)
→ Groq generates candidate rule
→ threat_candidates (status: pending_review)
→ admin review + approval
→ Ed25519-signed bundle published
→ proxy hot-reload within 60 seconds
The admin review step is intentional. Fully automated CVE-to-rule pipelines sound fast but produce noisy bundles. A rule that triggers on any request containing a version string from a vulnerable library will generate hundreds of false positives per day in real traffic. The LLM generates the candidate; a human makes it deployable.
The crowd-source loop
The NVD pipeline handles known CVEs. The crowd-source loop handles attack patterns that don't have a CVE yet — novel payloads, targeted probes, zero-day techniques appearing in production traffic before researchers have named them.
Every event in the ekmire dashboard has a false positive button. When a legitimate request gets blocked, the user marks it. That mark creates an audit.false_positive event, which adjusts the signal_weight on the corresponding threat candidate. Confirmed detections from multiple organisations increase weight (+0.5 per org, max 5.0); false positives decrease it. A daily pg_cron job decays all weights by ×0.9 (floor 0.1), so stale patterns fade from the queue without manual cleanup.
ekmire also runs pgvector semantic clustering on threat candidates. New candidates receive Gemini embeddings. Similar attack patterns — even when phrased or structured differently — cluster together, so the review queue shows groups of related attempts rather than disconnected noise. Five organisations independently seeing structurally similar attack payloads is a much stronger signal than five unrelated single reports.
When a crowd-sourced pattern has enough signal weight and passes admin review, it becomes a signed rule in the next bundle — covering an attack class the NVD pipeline would not have seen.
Why Ed25519 signing matters
A rule bundle that can be tampered with is worse than no rule bundle. An attacker who can inject a rule can allow their own traffic and block everyone else's — turning the WAF into a tool for their persistence.
Every ekmire rule bundle is signed with Ed25519 before publication. Every connected proxy verifies the signature before applying any update. A bundle with an invalid signature is rejected — the proxy continues running on the previous verified bundle and logs a verification failure event to the dashboard.
The update path itself cannot be used as an attack surface. The proxy will not apply a rule that did not come from ekmire's signing key, regardless of where it was fetched from or what the bundle claims about its version. See the rule bundle format reference for the full verification spec.
The Rule Feed in the dashboard
Users can see the current rule bundle version and rule metadata from the dashboard's Rules Feed page. The feed shows the active bundle version, loaded rule categories, severity distribution, and false positive rates per rule. It is read-only — users see what is running but cannot modify the bundle directly.
This is the same bundle your proxy is running. If a CVE-based rule shipped at 04:30 UTC this morning after the daily Edge Function run and admin approval, it appears in the feed and is already active on every proxy that completed its last 60-second check cycle.
Hot-reload without downtime
ekmire's proxy checks for a new signed bundle every 60 seconds. When a new bundle is available, the proxy fetches it, verifies the Ed25519 signature, and swaps it in atomically using an Arc<RwLock<>> in the Rust runtime. In-flight requests finish with the old bundle. New requests immediately use the new one. No requests are dropped. No restart. No traffic interruption.
This matters in two scenarios:
- New CVE, fast response. A critical injection vulnerability is published. The pipeline runs at 02:00 UTC, admin reviews and approves the candidate, and the rule is live on every connected proxy within an hour of approval — without any operator touching the production deployment.
- False positive, fast fix. A rule starts triggering on legitimate traffic. The admin adjusts or disables the rule, publishes a new bundle, and every proxy picks it up within 60 seconds — no restart, no redeployment.
What this means if you run a traditional WAF
If you are running Cloudflare WAF managed rules, ModSecurity, or a self-maintained NGINX ruleset, your new CVE coverage depends on your update cadence — a process with a human bottleneck at every step. The rules running today may not cover a CVE published three days ago.
ekmire's threat feed is not a replacement for your edge provider. It is a complement for the application-adjacent layer where you need rules tuned to your actual traffic — AI payload patterns, prompt injection attempts, MCP-layer attacks — rather than general-purpose web protection alone.
The two-line WAF post covers how to put the ekmire proxy in front of your application using Docker Compose. Once it is running, it connects to the threat feed automatically. New rules reach it without any action on your part.
Three things to take away
- Automated does not mean unreviewed. The LLM pipeline generates candidates. A human validates each one before it reaches a proxy. Speed and quality are separate steps in the same pipeline.
- Signing is not optional. A rule update mechanism that can be tampered with is an attack surface. Ed25519 verification before every bundle apply ensures the mechanism itself cannot be hijacked.
- Hot-reload makes rules operationally real. A detection rule that requires a container restart to deploy is a rule that will be delayed when you most need it. 60-second hot-reload means admin approval to live coverage is measured in minutes, not in the next deploy window.