ai newsMo., 19. Okt.
EilmeldungInside Prometheus: Meta’s Journey to a Gigawatt-Scale Supercluster

Veil: a local-first redaction gate for everything you paste into an AI

Last week I pasted a production database URL into a chat window. Nothing happened. That is exactly the problem. The paste box sits one keystroke away from the stack trace, the config file, the support ticket with a customer's name in it. Every AI chat UI warns you not to paste secrets, and then put

dev.toMontag 13:13 · 19.10.5 Min. Lesezeit
Bild: dev.to

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

Last week I pasted a production database URL into a chat window.

Nothing happened. That is exactly the problem. The paste box sits one keystroke away from the stack trace, the config file, the support ticket with a customer's name in it. Every AI chat UI warns you not to paste secrets, and then puts the box right there.

I built Veil to sit between the clipboard and the chat box. It runs on your machine, finds the credentials and the quieter contextual leaks, and replaces them with stable placeholders before anything is sent.

Veil is a local-first redaction gate with three surfaces:

It catches AWS keys, GitHub/Slack/Stripe/Google/OpenAI tokens, JWTs, PEM blocks, database URLs with inline passwords, card numbers (Luhn-checked), emails, phone numbers, private IPs, and internal hostnames. Then an open-weight Gemma model reads for the things regex cannot see: a customer's name, an internal codename, the sentence that says the document is under NDA.

Everything is MIT licensed, has zero runtime dependencies, and the model is swappable through VEIL_MODEL.

Here is a fake support ticket with a fake production config in it:

Customer: Priya Raman at Northwind Traders. Contact: priya.raman@northwind-traders.com / +1 415 555 0132 Internal project: HALCYON-7 Staging host: billing-api.corp.internal AWS_ACCESS_KEY_ID=AKIA... DATABASE_URL=postgres://veil_app:hunter2isbad@db-prod-01.corp.internal:5432/billing This ticket is under NDA with Northwind Traders. Enter fullscreen mode Exit fullscreen mode And here is what comes out the other side:

Customer: [PERSON_1] at [CUSTOMER_1]. Contact: [EMAIL_1] / [PHONE_1] Internal project: [PROJECT_1] Staging host: [HOST_1] AWS_ACCESS_KEY_ID=[AWS_KEY_1] DATABASE_URL=[DATABASE_URL_1] [CONFIDENTIAL_1]. Do not forward it outside the migration channel. Enter fullscreen mode Exit fullscreen mode The redacted version still reads like a document. You can tell that two lines mention the same value, because the same literal always gets the same placeholder. You cannot tell what the value was.

git clone https://github.com/shreya-oeo/veil cd veil npm test npm run fixtures node src/cli.js scan fixtures/support-ticket.md # rules only, ~3 ms node src/cli.js redact fixtures/support-ticket.md --model --model-name gemma4:cloud Enter fullscreen mode Exit fullscreen mode The CLI is pipe-friendly, so it also works as a gate:

git diff | veil redact --model > safe.diff kubectl logs api-0 | veil scan --json --fail-on high Enter fullscreen mode Exit fullscreen mode How it works The architecture follows one rule: a redaction tool must be correct, not creative.

flowchart LR A[Input] --> B[18 deterministic rules] A --> C[Entropy scan] A --> D[Gemma via Ollama] B --> E[Merge spans] C --> E D -->|quote must exist verbatim| E E --> F[Stable placeholders] Deterministic rules run first. A regex finds AKIA... with certainty. A small model does not. The model should never be asked to do a job that string matching already does perfectly.

Entropy catches the shape you did not write a rule for. A 32-character token with 5.1 bits of entropy per character, sitting next to SECRET=, is a credential even when no vendor prefix matches. Git SHAs, SHA-256 digests, and base64 images are allowlisted so the scan does not cry wolf.

The model runs second, and only suggests. It returns quotes. Every quote is checked character-for-character against the source:

const index = text. indexOf ( quote ); if ( index === - 1 ) { dropped += 1; continue; } Enter fullscreen mode Exit fullscreen mode If the model paraphrases, fixes a typo, or invents a plausible-looking secret, the span is discarded and counted. The UI shows the count. On this fixture the model returned four quotes and all four survived, but the number exists precisely because it will not always be zero.

Overlapping spans merge before anything is replaced. An AWS secret on an env line trips both a regex and the entropy scan; a JWT inside a URL trips two more. Replacing spans one at a time shifts every offset after the first, so Veil merges them first and keeps the most severe label. Model quotes that merely repeat a precise rule match are dropped, so an email stays [EMAIL_1] instead of becoming a vaguer [REDACTED_1].

My first version let the model's findings override the rules. The result was worse, not better: Gemma would return "Person name" for an email address, the merge would pick the higher severity, and the output would turn a precise [EMAIL_1] into a vague [REDACTED_1].

The fix was structural, not prompt-level. Rules own the categories they can prove. The model only gets to add spans the rules cannot see. That is a small change in the merge logic and a large change in how much I trust the output.

A redaction tool that uploads your text to a closed API to ask whether the text is sensitive has already lost the argument. The whole point is to keep the data on the machine that already has it.

That constraint is what made the design better:

The closed alternative is not just more expensive. It is structurally unable to make the promise Veil makes: your text did not leave this laptop.

I would rather be explicit about this than have someone trust it too much.

The tool also reports residual risk it cannot fix: local filesystem paths that reveal a username, health or identity terms, and documents marked confidential all produce a warning even when nothing matched.

OCR for screenshots, a pre-commit hook, and an editor extension that redacts on paste. The core is small enough that each of those is a surface, not a rewrite.

Code: https://github.com/shreya-oeo/veil Run it: git clone, npm test, node src/cli.js serve

Built for the Hacktoberfest Open-Source AI Challenge. Entering Best Use of Gemma — the model pass is what turns a regex filter into something that catches a customer's name and an NDA sentence, not just a key.

Quelle: dev.to (dev.to). Original öffnen