DEV Community

Avishi Shreya
Avishi Shreya

Posted on

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

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

What I Built

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 a stack trace, a config file, or a support ticket containing a customer's personal information. Every AI chat UI warns you not to paste secrets, and then puts the box right there.

I built Veil, a local-first redaction gate that sits between your text and the AI chat box. It scans text for credentials, personal information, internal identifiers, and contextual leaks, then replaces sensitive content with stable placeholders before you send it anywhere.

Veil's local UI: sensitive input on the left, redacted output and a findings list on the right

Veil has three interfaces:

  • CLI: veil scan, veil redact, and veil doctor
  • Local web UI: Runs on 127.0.0.1:4317
  • Node.js library: Integrate scanning with scan(text, { client, useModel })

It detects AWS keys, GitHub/Slack/Stripe/Google/OpenAI tokens, JWTs, PEM blocks, database URLs with inline passwords, Luhn-checked card numbers, emails, phone numbers, private IPs, and internal hostnames.

Then an open-weight Gemma model looks for contextual information that deterministic rules cannot reliably identify, such as a customer's name, an internal codename, or a sentence indicating that a document is under NDA.

The project is MIT licensed, has zero runtime dependencies, and supports swapping models through VEIL_MODEL.

Demo

Imagine pasting this support ticket into an AI assistant:

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

Veil transforms it into:

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 output remains readable. Repeated occurrences of the same value receive the same placeholder, preserving context without exposing the original information.

The project includes a local web interface and a CLI for trying the redaction pipeline.

Run the demo yourself:

git clone https://github.com/shreya-oeo/veil
cd veil
npm test
npm run fixtures
node src/cli.js serve
Enter fullscreen mode Exit fullscreen mode

To inspect the sample fixture:

node src/cli.js scan fixtures/support-ticket.md
node src/cli.js redact fixtures/support-ticket.md --model --model-name gemma4:cloud
Enter fullscreen mode Exit fullscreen mode

You can also use Veil in shell pipelines:

git diff | veil redact --model > safe.diff
kubectl logs api-0 | veil scan --json --fail-on high
Enter fullscreen mode Exit fullscreen mode

Demo screenshot: https://raw.githubusercontent.com/shreya-oeo/veil/main/docs/screenshot.png

Code

GitHub repository: https://github.com/shreya-oeo/veil

The project is built around a small, inspectable pipeline rather than a large framework.

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]

The main design principle is simple: a redaction tool must be correct, not creative.

  • Deterministic rules run first. A regex can recognize a known AWS key format reliably. A language model is unnecessary for that job.
  • Entropy scanning catches unknown secrets. High-entropy strings near indicators such as SECRET= can be flagged even when they lack a recognized vendor prefix. Known formats such as Git SHAs, SHA-256 digests, and base64 images are allowlisted to reduce false positives.
  • Gemma suggests additional sensitive spans. The model returns quoted fragments, and Veil verifies every quote character-for-character against the original text. Invented or paraphrased quotes are discarded.
  • Overlapping findings are merged. This prevents multiple detectors from producing conflicting placeholders for the same sensitive value.
  • Precise detections take priority. Model findings that merely repeat a deterministic match are discarded so that an email remains [EMAIL_1] rather than becoming a generic [REDACTED_1].

I learned an important lesson during development: my first version let the model's findings override deterministic rules. Gemma could identify an email as a person's name, and the merge logic would replace a precise label with a vague one.

The fix was architectural, not prompt-based. Rules own the categories they can prove; the model can only add findings that the rules miss.

The project currently includes 18 deterministic rules and 34 tests using Node's built-in test runner, including tests for invented quotes and quotes differing by a single space.

How I Built It

Veil combines three approaches:

1. Deterministic detection

Regular expressions and specialized validators identify known credentials and sensitive formats. These are predictable, fast, and easy to audit.

2. Shannon entropy analysis

Entropy scanning identifies suspicious high-entropy strings that do not match known credential patterns. Allowlisting helps avoid flagging common hashes and encoded content indiscriminately.

3. Open-weight AI with Gemma

Gemma handles the contextual detection layer: information that may be sensitive because of what it means, rather than simply how it looks.

The model does not get the final say. Its quoted findings must exist verbatim in the original text before they can enter the redaction pipeline.

The implementation uses Node.js built-ins such as http, fs, and fetch, without third-party runtime dependencies. The UI is a single HTML file with no CDN requests, external fonts, or analytics.

I tested Gemma through Ollama's cloud model tag because downloading a local model was impractical with my connection. The same pipeline can use a local model by setting VEIL_MODEL=gemma3:4b or VEIL_MODEL=gemma3:1b, subject to the selected model being available. The UI distinguishes cloud-routed models from local inference rather than claiming that every configuration is offline.

One unexpected challenge was GitHub's push protection: committing fixtures containing credential-shaped strings caused the initial push to be blocked. I changed the fixtures to generate the sample data at runtime instead.

Why Does Open Innovation Matter?

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

Open innovation made several aspects of Veil possible:

  • An inspectable trust boundary: Anyone can review the detection rules, inspect the source, and configure the model endpoint. There is no account, telemetry, or per-token bill built into the redaction pipeline.
  • A replaceable AI component: Gemma performs a narrow task: identifying contextual fragments that deterministic rules may miss. Other compatible models can be substituted without redesigning the entire pipeline.
  • Affordable privacy checks: A privacy tool should be practical to run repeatedly, including on every diff or log stream, without paying for every scan.
  • Community-owned detection: MIT licensing allows developers to add credential formats and sensitive-data patterns relevant to their own projects without waiting for a vendor.
  • The ability to run locally: With an available local model, the entire pipeline can run without sending the text to a remote inference provider.

Open weights also let developers inspect and experiment with the AI component instead of treating it as an inaccessible service.

For Veil, open innovation is not just about saving money or avoiding vendor lock-in. It makes the privacy boundary more transparent and gives users control over where their data goes.

The promise is straightforward: with a fully local configuration, your text does not need to leave your machine to be checked for sensitive information.

My Agent Session

No agent session link included in this submission.

The Lazy Payoff

Veil is designed to remove the repetitive work of manually checking text before pasting it into an AI assistant.

Instead of hunting through a support ticket, config file, log stream, or code diff for every possible secret, you can scan or redact the entire input with one command.

The deterministic scan runs in approximately 3 ms on the sample fixture, according to my local testing. The model-assisted pass adds inference latency, but it can identify contextual leaks that regex alone would miss.

The practical payoff:

  • Less manual redaction before using AI coding assistants.
  • Fewer opportunities to accidentally expose credentials in logs and diffs.
  • Consistent placeholders that preserve the structure and readability of documents.
  • A reusable CLI and library instead of a one-off cleanup script.

Veil does not make sharing sensitive information risk-free, and a clean scan is not a guarantee that a document contains no sensitive data. It is an additional layer of protection, not a substitute for judgment.

Prize Categories

  • Best Use of Gemma — Gemma provides the contextual detection layer that complements deterministic rules, helping Veil identify names, internal project identifiers, and confidentiality-related text that pattern matching alone may miss.

What's Next?

The next steps are OCR for screenshots, a pre-commit hook, and an editor extension that redacts text on paste.

The core is intentionally small, so these can be added as new integration surfaces rather than requiring a complete rewrite.

Built for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady.

Code: https://github.com/shreya-oeo/veil

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

Top comments (0)