<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Avishi Shreya</title>
    <description>The latest articles on DEV Community by Avishi Shreya (@avishishreya).</description>
    <link>https://dev.to/avishishreya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F99mvlsfu5tfj9m7ku25d.png</url>
      <title>DEV Community: Avishi Shreya</title>
      <link>https://dev.to/avishishreya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/avishishreya"/>
    <language>en</language>
    <item>
      <title>Veil: a local-first redaction gate for everything you paste into an AI</title>
      <dc:creator>Avishi Shreya</dc:creator>
      <pubDate>Tue, 20 Oct 2026 14:50:38 +0000</pubDate>
      <link>https://dev.to/avishishreya/veil-a-local-first-redaction-gate-for-everything-you-paste-into-an-ai-2a8d</link>
      <guid>https://dev.to/avishishreya/veil-a-local-first-redaction-gate-for-everything-you-paste-into-an-ai-2a8d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Last week I pasted a production database URL into a chat window.&lt;/p&gt;

&lt;p&gt;Nothing happened. That is exactly the problem.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Veil&lt;/strong&gt;, 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F76to48kes2188nf3dwgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F76to48kes2188nf3dwgc.png" alt="Veil's local UI: sensitive input on the left, redacted output and a findings list on the right" width="800" height="1518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Veil has three interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI:&lt;/strong&gt; &lt;code&gt;veil scan&lt;/code&gt;, &lt;code&gt;veil redact&lt;/code&gt;, and &lt;code&gt;veil doctor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local web UI:&lt;/strong&gt; Runs on &lt;code&gt;127.0.0.1:4317&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js library:&lt;/strong&gt; Integrate scanning with &lt;code&gt;scan(text, { client, useModel })&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The project is MIT licensed, has zero runtime dependencies, and supports swapping models through &lt;code&gt;VEIL_MODEL&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Imagine pasting this support ticket into an AI assistant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veil transforms it into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output remains readable. Repeated occurrences of the same value receive the same placeholder, preserving context without exposing the original information.&lt;/p&gt;

&lt;p&gt;The project includes a local web interface and a CLI for trying the redaction pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run the demo yourself:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/shreya-oeo/veil
&lt;span class="nb"&gt;cd &lt;/span&gt;veil
npm &lt;span class="nb"&gt;test
&lt;/span&gt;npm run fixtures
node src/cli.js serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To inspect the sample fixture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node src/cli.js scan fixtures/support-ticket.md
node src/cli.js redact fixtures/support-ticket.md &lt;span class="nt"&gt;--model&lt;/span&gt; &lt;span class="nt"&gt;--model-name&lt;/span&gt; gemma4:cloud
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use Veil in shell pipelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff | veil redact &lt;span class="nt"&gt;--model&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; safe.diff
kubectl logs api-0 | veil scan &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="nt"&gt;--fail-on&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Demo screenshot:&lt;/strong&gt; &lt;a href="https://raw.githubusercontent.com/shreya-oeo/veil/main/docs/screenshot.png" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/shreya-oeo/veil/main/docs/screenshot.png&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/shreya-oeo/veil" rel="noopener noreferrer"&gt;https://github.com/shreya-oeo/veil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is built around a small, inspectable pipeline rather than a large framework.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Input] --&amp;gt; B[18 deterministic rules]
    A --&amp;gt; C[Entropy scan]
    A --&amp;gt; D[Gemma via Ollama]
    B --&amp;gt; E[Merge spans]
    C --&amp;gt; E
    D --&amp;gt;|Quote must exist verbatim| E
    E --&amp;gt; F[Stable placeholders]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The main design principle is simple: &lt;strong&gt;a redaction tool must be correct, not creative.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic rules run first.&lt;/strong&gt; A regex can recognize a known AWS key format reliably. A language model is unnecessary for that job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy scanning catches unknown secrets.&lt;/strong&gt; High-entropy strings near indicators such as &lt;code&gt;SECRET=&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma suggests additional sensitive spans.&lt;/strong&gt; The model returns quoted fragments, and Veil verifies every quote character-for-character against the original text. Invented or paraphrased quotes are discarded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overlapping findings are merged.&lt;/strong&gt; This prevents multiple detectors from producing conflicting placeholders for the same sensitive value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precise detections take priority.&lt;/strong&gt; Model findings that merely repeat a deterministic match are discarded so that an email remains &lt;code&gt;[EMAIL_1]&lt;/code&gt; rather than becoming a generic &lt;code&gt;[REDACTED_1]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Veil combines three approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Deterministic detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regular expressions and specialized validators identify known credentials and sensitive formats. These are predictable, fast, and easy to audit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Shannon entropy analysis&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;3. Open-weight AI with Gemma&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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 &lt;code&gt;VEIL_MODEL=gemma3:4b&lt;/code&gt; or &lt;code&gt;VEIL_MODEL=gemma3:1b&lt;/code&gt;, subject to the selected model being available. The UI distinguishes cloud-routed models from local inference rather than claiming that every configuration is offline.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Open innovation made several aspects of Veil possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An inspectable trust boundary:&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A replaceable AI component:&lt;/strong&gt; Gemma performs a narrow task: identifying contextual fragments that deterministic rules may miss. Other compatible models can be substituted without redesigning the entire pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Affordable privacy checks:&lt;/strong&gt; A privacy tool should be practical to run repeatedly, including on every diff or log stream, without paying for every scan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community-owned detection:&lt;/strong&gt; MIT licensing allows developers to add credential formats and sensitive-data patterns relevant to their own projects without waiting for a vendor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ability to run locally:&lt;/strong&gt; With an available local model, the entire pipeline can run without sending the text to a remote inference provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open weights also let developers inspect and experiment with the AI component instead of treating it as an inaccessible service.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The promise is straightforward: &lt;strong&gt;with a fully local configuration, your text does not need to leave your machine to be checked for sensitive information.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;No agent session link included in this submission.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;Veil is designed to remove the repetitive work of manually checking text before pasting it into an AI assistant.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;The practical payoff:&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The next steps are OCR for screenshots, a pre-commit hook, and an editor extension that redacts text on paste.&lt;/p&gt;

&lt;p&gt;The core is intentionally small, so these can be added as new integration surfaces rather than requiring a complete rewrite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/shreya-oeo/veil" rel="noopener noreferrer"&gt;https://github.com/shreya-oeo/veil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;git clone https://github.com/shreya-oeo/veil&lt;/code&gt;, then &lt;code&gt;npm test&lt;/code&gt; and &lt;code&gt;node src/cli.js serve&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hacktoberfest</category>
      <category>privacy</category>
      <category>security</category>
    </item>
  </channel>
</rss>
