Skip to content
← BACK TO JOURNAL
BUILDS . MAR 14 . 5 MIN

How we built Obscura (local-first PII redaction).

BB
Braeden Bihag

We built Obscura local-first because the moment a redaction tool lives on a server, it has already lost. The whole problem is that people paste customer data, signed contracts, and internal revenue numbers into ChatGPT, and they do it because opening a separate tool is more friction than the risk feels worth. So the core decision was simple: put the redaction where the leak happens, in the browser, before the prompt leaves the machine. Zero bytes go anywhere. A detection model compiled to WebAssembly runs entirely browser-side, intercepts the prompt, strips the sensitive parts, then sends the cleaned text. No round trip, no server we could be subpoenaed for, no second app to open.

Why local-first was non-negotiable

If Obscura sent prompts to our backend to scan them, we would be the data breach we are trying to prevent. Think about it. To redact a contract, we would have to receive the contract first. That is absurd. It also fails the only test that matters for a security tool, which is whether a paranoid CISO will install it. A paranoid CISO is correct to be paranoid, and the answer to every one of their questions has to be the same: nothing leaves the browser.

So everything runs client-side. The detection model is compiled to WebAssembly and ships inside the extension. It loads once, runs in the page, and never phones home. There is no telemetry, no usage ping, no model call to an inference endpoint. We measured success not in latency dashboards but in a single property we could state plainly and have it be true: 0 bytes leave the browser.

A redaction tool that needs to see your data to redact it is just a slower way to leak it.

Why a browser extension beat an SDK

My first instinct as an engineer was an SDK. Clean API, drop it into the client's app, done. I was wrong, and I am glad I caught it early. An SDK means someone has to integrate it. That means a ticket, a sprint, a security review, a deploy. By the time all of that clears, the marketing manager has already pasted the quarterly numbers into ChatGPT forty times. The friction we were fighting would have moved into the install instead of being removed.

A browser extension goes exactly where the behavior is. People use ChatGPT in a tab. Obscura lives in that tab. It intercepts the prompt at the point of submission, runs detection, redacts, and only then lets the text through. One install, no integration, no code change on the client side. The extension form factor is not a compromise. It is the product working at the layer the problem actually exists on.

  • SDK: requires client engineering time, a deploy, and a security review before it protects anyone.
  • Extension: one click, protects the very next prompt, no integration debt.
  • The leak happens in the browser, so the guard belongs in the browser.

How detection actually works: NER plus regex

Detection is a mix of two approaches because the data is two kinds of thing. Named-entity recognition handles the fuzzy stuff: names, organizations, locations, the parts of language where context decides whether a word is sensitive. The model handles 56 entity types in total. But NER is the wrong tool for structured tokens. An IBAN has a checksum. An email has a shape. A license plate follows a format. You do not want a probabilistic model guessing at those when a regex matches them exactly, every time, with no false negatives on the patterns you care about.

So we run both. Regex catches emails, IBANs, license plates, and the internal codenames a client tells us about, the made-up project words that no general model would ever flag. NER catches the entities that need understanding. The two layers cover for each other. Regex gives you precision on anything with a format. NER gives you recall on anything that depends on meaning. Run them together and you stop both the credit card number and the customer's name in the same pass, before either one reaches the prompt box.

Why MIT, and why the free tool comes first

We released Obscura under MIT for one reason: a security team cannot trust a black box, and they should not. If I were vetting a tool that promised nothing leaves the browser, I would want to read the code and confirm the binary matches it. MIT lets them do exactly that. They can build it themselves, diff it against what we ship, and verify the claim instead of believing my blog post. Trust you can audit is the only kind worth offering for this category.

That is also why the free, open tool ships before the paid product. The open-source extension is how a security team comes to trust the engine. It is already adopted internally by a few of our agency clients, which is the proof that matters more than any benchmark I could quote. The SaaS version is the natural follow-up, and it is honest about being a different thing: same detection engine, different distribution. The paid layer adds centralized policy, audit logs, and fleet management, the things an org needs once the tool is on a hundred machines. The engine earns trust as FOSS. The SaaS sells the operational wrapper around an engine people already believe in. We built the whole thing in a Forge sprint, and keeping the trust layer free was the part we were least willing to negotiate.

// frequently asked
Does any prompt data reach Almost a Lab's servers?

No. Obscura runs fully local. The detection model is compiled to WebAssembly and executes in your browser. It intercepts the prompt, redacts it, and sends the cleaned text onward. 0 bytes leave the browser, and there is no telemetry.

Why a browser extension instead of an SDK we integrate?

Because an SDK needs client engineering time, a deploy, and a security review before it protects anyone, and people are pasting sensitive data the whole time that takes. An extension installs in one click and guards the very next prompt, with no code change on your side. The leak happens in the browser, so the guard belongs there.

What can Obscura detect?

56 entity types, using NER for context-dependent entities like names and organizations, and regex for structured tokens like emails, IBANs, license plates, and client-specific internal codenames. The two layers run together so format-based and meaning-based sensitive data are both caught in a single pass.


Brief a build →