DEV Community

Cover image for I built the first OSS federated threat-intel feed for LLM prompt injection. Here's how it works — and why no one else did.
Thamilvendhan Munirathinam
Thamilvendhan Munirathinam

Posted on • Originally published at github.com

I built the first OSS federated threat-intel feed for LLM prompt injection. Here's how it works — and why no one else did.

Every open-source LLM prompt-injection defense tool I've looked at — Lakera, ProtectAI, NeMo Guardrails, Guardrails AI, Llama Guard, Cisco AI Defense — has one thing in common. None of them ship a public federated threat-intel feed.

That's strange, because we've had this pattern in security infrastructure for twenty years. WAFs pull hourly signature updates from OWASP CRS. AV clients pull daily updates from ClamAV. Even IDS platforms consume Emerging Threats' free feed. Every layer of defense infrastructure has some version of "phone home for the latest attack patterns."

Everyone except LLM defense.

So I built one for prompt-shield v0.6.0. It's pure-Python ed25519-verified, hosted on a free CDN, opt-in, and Apache 2.0. Currently 1-2 confirmed subscribers (there's a live counter on the README). Let me walk through how it works.

Why nobody else did it

The answer isn't technical difficulty. It's about incentives.

  • Lakera, ProtectAI (now Palo Alto), Cisco AI Defense — commercial. Their threat intel is what they sell. Open-sourcing it kills their business model. They're structurally locked out of shipping this, even if their engineers want to.
  • NeMo Guardrails, Llama Guard — big-co research projects. No maintenance commitment for the boring infrastructure work of curating a feed month after month.
  • Guardrails AI — has a validator marketplace, but it's a one-way hub. Contributors add validators; they don't push a real-time signature delta to every deployed instance.

That leaves the OSS/solo-maintainer bucket, where the only real question is "does anyone have the persistence to maintain this?" I don't know if I do yet, but v0.6.0 is the first attempt.

What the feed actually is

Three files on a public GitHub repo, served via jsDelivr's free CDN:

  • signatures.json — the payload. Currently 56 curated attack signatures. Each has an ID, a YAML regex pattern, a severity, a source attribution, and a first-seen date.
  • signatures.json.minisig — an ed25519 detached signature over the JSON, in the minisign format.
  • public.key — the maintainer's public key (also embedded in prompt-shield's source as a defensive measure against MITM'd downloads).

The client library polls the CDN, verifies the signature, and merges the parsed rules into prompt-shield's existing custom-rules engine (d030). Full round trip is ~200 lines of Python.

Where do the signatures come from? Right now:

  • 18 from the NVIDIA Garak red-team corpus
  • 22 from OWASP LLM Top 10 disclosed examples
  • 12 from public HackerOne LLM disclosures
  • 4 from community submissions during development

Each signature is a real attack pattern, hand-curated for high precision. No auto-generated stuff.

The design constraints

Three things I refused to compromise on:

  1. No telemetry. The client tells the CDN "give me the file." That's it. No user ID, no API key, no analytics beacon. This means the ONLY way I can measure adoption is via the CDN's public request-count endpoint — which I've exposed as a live badge on the README so the number's honest.

  2. Cryptographic verification, no auth server. Anyone can fetch the feed. But the client verifies the ed25519 signature against a pinned public key before applying any of it. If someone MITMs the CDN and injects malicious signatures, the verify fails and the client falls back to its local cache. No auth server means no operational burden and no offline-mode-blocking dependency.

  3. Fail-safe on verify failure. Verification failure never overwrites the local cache. The last known-good payload stays in effect until the client fetches something valid. Worst case: a broken CDN means subscribers stop getting updates. Best case: no way for a compromised transport to poison the detection engine.

The 3-line client

Here's the entire subscribe path:

from prompt_shield.signatures import SignaturesClient

update = SignaturesClient().fetch()
# update.signature_count == 56
# ed25519-verified against pinned key 31F125ADDE54B24A
Enter fullscreen mode Exit fullscreen mode

That's it. SignaturesClient() has sensible defaults: default feed URL, default public key, 24-hour local cache path, 60-second throttle to prevent hammering the CDN. You can wire it into a cron job, a background thread, or a systemd timer — the client itself does no polling. Fetch when you want, throw the result at your engine.

Threat model — the honest bits

I've spent more time on the threat model than the code, because for a defense tool this matters more than most features. Three attacks I've thought about:

Key compromise. If my ed25519 signing key gets stolen, I have to rotate and break every existing subscriber. Not solved yet. The v0.7 roadmap has a key-rotation policy but implementing it well is hard (how do you rotate without breaking offline clients that haven't polled since before the rotation?). Open to smart ideas here.

CDN compromise. jsDelivr is the transport. If they get compromised and serve malicious JSON, the signature check fails, subscribers fall back to their cache. Worst case: no updates until CDN recovers. No malicious data is ever applied.

Maintainer compromise. If someone compromises me and ships malicious signatures via my key, subscribers apply them. Mitigation baked into the design: signatures are additive only — they can flag prompts as malicious but cannot disable existing detectors. So the worst-case outcome is some false positives, not a bypass of the whole detection engine. This is important. If I get compromised, no defense subscriber gets weaker; they might just get noisier for a few hours until I rotate.

Bus factor of 1. This is the real problem. Everything above assumes I'm around to maintain the signing key, curate signatures, review community submissions, and rotate on compromise. If I get hit by a bus, the feed goes stale immediately. I don't have a solution to this yet. If you're an OSS-security-minded engineer who wants to co-maintain, open an issue and let's talk.

Where this is right now

Current state, verifiable from public sources:

  • 56 signatures live in the v1 feed
  • 1-2 confirmed production subscribers (live jsDelivr-request badge on the README)
  • 17 hermetic tests + 1 live-network test in the shipped client
  • v0.6.0 released 2026-06-25 with the client; v0.6.1 (2026-06-25) is a compliance/docs patch

If you want to try it:

pip install prompt-shield-ai
Enter fullscreen mode Exit fullscreen mode
from prompt_shield.signatures import SignaturesClient
print(SignaturesClient().fetch())
# SignaturesUpdate(success=True, signature_count=56, source='remote')
Enter fullscreen mode Exit fullscreen mode

And if you deploy it in production, thank you — you become the second or third subscriber, and the badge ticks up publicly.

The compounding argument

The pitch for using this — beyond "it's free" — is that federated threat intel gets better with adoption, not worse. Every new prompt-shield deployment can (eventually — the submission API is v0.7 work) contribute anonymized attack fingerprints back to the feed. That means the more people use it, the higher the signature coverage, the better the detection for everyone.

Commercial competitors can't do this without giving away their business model. OSS is the only architecture that can. That's why building it as OSS-first isn't just ideology — it's the only way this shape of infrastructure has ever worked, going back to Snort rules and OWASP CRS.

If you build in the LLM security space, you should have opinions about this. Even if my implementation is wrong, someone should ship the pattern. Come argue about it in the issues — that's how we get a better v0.7.

Links

Top comments (0)