SieveGate: a zero-trust gate for LLM prompts
A Python library that sits in front of every call your code makes to an LLM API. Before a prompt leaves, it screens it for secrets, personal data and other sensitive content, then either blocks it or lets it through with a recommended model tier. If anything goes wrong, the answer is always "blocked".
The problemPrompts are an exit door for data
People paste whatever they are working on into AI tools: stack traces with database passwords, customer records, private keys, patient notes. Once a prompt reaches a third-party LLM API, that data has left your control. At the same time, many teams send every request to their largest and most expensive model, even the simple ones a small model would handle well. SieveGate addresses both with a single decision point.
How it worksFour stages, first "no" wins
- Modality checkVersion 1 screens text only. Images, files and empty input are blocked outright.
- Local pre-filterTwelve high-precision detectors (private keys, cloud and API keys, JWTs, credentialed URLs, Luhn-checked card numbers, SSA-valid SSNs, mod-97-checked IBANs) run on your machine using only the Python standard library. A finding blocks the payload before anything is sent.
- Jev classifierEverything else gets one call to a fast structured-decision model (TypeSafe's Jev) that answers six questions at once: personal data, secrets, financial records, leak risk, content category and model tier. Each answer comes back as a probability or score, not just a yes or no.
- Enforcement policyA configurable set of thresholds and blocked categories turns those answers into a decision. Every rule is evaluated and every hit is recorded as a reason code. Some categories, like financial records, pass but ask a person to reconfirm first.
SieveGate returns a decision and never makes the LLM call itself, so it drops into an existing application with a few lines of code.
Design decisionsWhat makes it a security tool
- Fail-secure. A timeout, a classifier error, a malformed answer, or even a bug in the policy all lead to the same outcome: BLOCKED. There is one timeout and one blocked path. Out-of-range signals and NaN values are rejected too, because a NaN compares false with every threshold and would otherwise slip past every rule.
- Vendor-swappable classifier. The gate depends on an abstract
Classifierinterface, and the policy reads only vendor-neutral fields such aspii_probabilityandcontent_category. Jev can be replaced without touching the policy. - The pre-filter can only tighten the gate. It blocks, or it defers to the classifier. It never marks anything as safe.
- No payload text in logs. Results carry reason codes and exception type names only. SDK error messages can echo the request body, so they are never copied. The adapter also stops the vendor SDK from logging request bodies at DEBUG level, and the test suite plants canary strings to prove nothing leaks.
- Immutable, auditable results. Every decision is a frozen object listing the reason of every rule that fired.
- Regexes hardened against hostile input. Every pattern is anchored so a long run of token characters has only one possible match start. A 1 MB payload scans in about 110 ms.
- Observe mode. The policy can run in full without blocking, so a team can measure false blocks on real traffic before turning enforcement on.
See it in actionFive of the fifteen demo scenes
The demo runs the real gate, pre-filter and policy locally with no API key. The classifier is replaced by a replay of answers recorded from a live Jev run on 6 October 2026.
A private key pasted into "why won't SSH work?"
Caught by the local pre-filter in under a millisecond. Jev was never called, so the payload never left the machine.
A patient note: no pattern to match, but clearly sensitive
There is no ID number or key format here, so the pre-filter found nothing. Jev recognised health information about a named person, and three independent policy rules blocked it. This is why there are two layers: the pre-filter catches formats, and Jev catches meaning.
A base64-encoded credential
Encoding hides the secret from pattern matching. Jev saw through it (secret probability 0.90) and the policy blocked it.
A plain question
Normal traffic is not punished. It passes, with the cheapest tier recommended.
A simulated classifier outage
The classifier never answers. When the timeout fires, the gate blocks the payload. No answer means no send.
ResultsThe numbers, honestly
Measured once on a holdout set of 300 fake payloads that were never used for tuning (6 October 2026). 298 were scored: 207 that should be blocked and 91 that should pass. The thresholds were tuned earlier on two separate sets of 70 and 259 payloads, and the answer key stayed outside the project until the run finished.
| Measure | Result | Target |
|---|---|---|
| Dangerous payloads caught | 206 of 207 (0.5% false-pass) | Met false-pass ≤ 3% |
| Stopped locally, no network call | 20 of 207 (9.7%) | n/a |
| Harmless payloads blocked | 17.6% (16 of 91) | Missed ≤ 10% |
| Overall accuracy | 94.3% (281 of 298) | Missed ≥ 95% |
| Latency per classifier decision | median 111 ms, p90 143 ms | Met p90 < 1 s |
Two of the four targets were missed, and I am saying so. The defaults are zero-trust, so when in doubt the gate blocks. That kept dangerous payloads that got through to 1 in 207, at the cost of blocking 16 harmless ones. Most of those 16 were lookalike traps written to resemble dangerous content on purpose. I reviewed them and accepted the trade-off for a security gate. Every threshold, blocked category and detector can be loosened.
LimitationsKnown limitations
- Text only. Images and files are blocked, not screened. When conversion is added it will have to run locally, because sending an image to a cloud OCR service would itself be the leak.
- The classifier vendor is a subprocessor. Any payload the pre-filter lets through is sent to TypeSafe for classification. Only modality, pre-filter and fail-secure blocks stay entirely on the machine.
- No Unicode normalisation in the pre-filter. Look-alike or full-width obfuscation is left to the classifier.
- Routing is advisory and unvalidated for cost claims. Tier accuracy was 82.4% on the holdout, so I publish no savings figures.
ProcessHow it was built
I designed SieveGate: the architecture, the security model (zero-trust defaults, fail-secure handling, local pre-filtering), the evaluation method and every product and policy decision. Every phase was verified with offline tests (333 in the public edition) and blind payload sets, and each decision is recorded in a project decision log.
Tech stack
- Python 3.10+
- asyncio
- frozen dataclasses
- TypeSafe Jev
- stdlib-only pre-filter
- pytest
- canary leak tests
- adversarial regex timing tests
The public repository is a view-only showcase edition. The code is all rights reserved, and you may read it and run the demo and tests to evaluate it.