Model or dataset
sgasser/pasteguard avatar
sgasser/pasteguard

PasteGuard: a local masking proxy for chat, APIs and coding agents

AI gets the context. Not your private data. Local-first privacy proxy for browser chat, AI APIs, and coding agents.

750 stars38 forksTypeScriptApache-2.0

At a glance

What is it?
PasteGuard sits between your application and an AI provider, replacing names, emails and API keys with placeholders before the request leaves your machine. The idea is sound and the deployment is one Docker command, but the semantic detection layer depends on GLiNER, and the browser extension is still described as experimental.
Who is it for?
Adopt PasteGuard if you already route model traffic through a base URL you control and want masking applied at that chokepoint rather than inside each application. Do not adopt it if your sensitive data is mostly free-form narrative, since the semantic layer rests on GLiNER alone, or if you need a hardened browser extension today, because the README still labels it experimental.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 22 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap PasteGuard fills between cloud AI and sensitive input

Teams that handle client records, candidate details, support tickets or production logs usually face four options, and the README lists them plainly: do not use cloud AI for sensitive work, redact by hand, fall back to a local model even when a cloud provider would give better results, or write one-off masking code inside every application. PasteGuard aims at the fourth option by turning masking into a shared service instead of a per-app feature. You run it locally or self-host it, and applications talk to it instead of talking to the provider.

The audience is narrower than the tagline suggests. This is for engineers who already control the base URL their application or agent uses, and who want the substitution to happen at one place rather than in five codebases. A single developer pasting a paragraph into a chat window is a secondary case, handled by the browser extension. The primary case is a codebase or an agent configuration where a URL can be swapped.

Mask Mode, Route Mode, and what actually travels upstream

Two operating modes are documented. In Mask Mode, PasteGuard replaces PII and secrets with placeholders before forwarding the request, and restores supported placeholders in the response before it returns to the caller. The word supported is doing real work there: the README does not enumerate which response shapes get restored, so the safe assumption is that restoration is not universal.

Route Mode takes a different path. Requests that contain sensitive data are sent to a local LLM such as Ollama, vLLM or llama.cpp, while requests without sensitive data can still go to the configured cloud provider. That is a routing decision made per request rather than a transformation, and it changes the cost profile: you need local inference capacity available, and the answer quality for the sensitive subset is whatever your local model produces.

Detection itself combines two kinds of check. Structured values get checksums and format checks, which is why credit cards, IBANs, EU VAT numbers and provider API keys can be matched with high confidence. Names and locations have no checksum, so they go through a semantic backend. GLiNER is currently the only backend, per the README, and the detector directory pairs it with python-stdnum. That single-backend situation is the main architectural constraint: swap-out is documented as a concept, but there is only one implementation to point at today.

Getting a proxy running on port 3000

The quick start is one command:

docker run --rm -p 3000:3000 ghcr.io/sgasser/pasteguard:latest

The dashboard is then at localhost:3000. Routing is path-based, and the README gives a table of substitutions. OpenAI traffic goes to http://localhost:3000/openai/v1 in place of https://api.openai.com/v1. Anthropic goes to http://localhost:3000/anthropic in place of https://api.anthropic.com. The Codex CLI target is http://localhost:3000/codex in place of https://chatgpt.com/backend-api/codex.

On the client side the change is a base URL. The README's Python example constructs OpenAI(base_url="http://localhost:3000/openai/v1"), and both client.chat.completions.create(...) and client.responses.create(...) are said to pass through the privacy pipeline. For anything beyond a trial run, the README points at the docs for custom config, persistent logs, Docker Compose and custom GLiNER models. Storage is SQLite or Postgres, and every request is logged with masking details, which is what the dashboard renders. Note the default: the docker run line above has no volume mount, so with --rm the log does not survive the container.

The detection layer is the part to interrogate

Structured secrets are the easy half. An API key prefix plus a checksum, or an IBAN with a valid check digit, gives you a decision procedure that does not need a model. The README claims coverage for OpenAI, Anthropic, Stripe, AWS and GitHub keys, SSH and PEM private keys, JWT and bearer tokens, passwords and connection strings. Passwords and connection strings are the ones I would not take on faith, because neither has a fixed format. A password is only recognizable in context, which puts it in the semantic bucket even though it sits in the secrets list.

The hard half is names and places. GLiNER handles those, and the README is explicit that it is currently the only backend. That means detection quality for unstructured personal data is a function of one model's behaviour on your text, in whatever languages you operate in. The README states detection is multilingual but does not list the languages. If your sensitive data lives mostly in prose rather than in fields, this is the component to test before anything else, and the docs path for custom GLiNER models is the escape hatch.

Where PasteGuard is the wrong tool

Masking is a transformation, not a guarantee. If a name survives detection, it reaches the provider in the clear, and no amount of local logging changes that. The README is honest about the boundary, stating that PasteGuard can support regulated workflows but does not replace a legal, security or compliance program. Read that as: this is a control point, not a compliance certification.

The browser extension carries its own caveat. The README calls it experimental and lists it for ChatGPT, Claude and Gemini. Experimental is a load-bearing label for a component that reads and rewrites text inside a third-party web page, and it is the least predictable of the three surfaces because the provider's DOM is not yours to control.

Route Mode has a failure mode worth naming. It sends sensitive requests to a local model, so the quality of the answer for exactly the requests you care most about is bounded by the local model you can afford to run. If your work depends on frontier reasoning over sensitive input, Route Mode trades capability for locality, and Mask Mode is the only other door.

There is also a single point of failure by design. Every request in the path now depends on the proxy being up. A self-hosted PasteGuard that goes down takes your AI traffic with it.

How this differs from building masking into the application

The obvious alternative is a library in your own codebase: call a redaction function before you construct the request, and un-redact the response yourself. Microsoft Presidio is the common reference point for that approach, and it is a Python library you embed rather than a service you route through.

The difference is where the chokepoint lives. A library gives you direct control over the detection rules and no extra network hop, but you have to implement it in every service, every language and every agent configuration, and streaming responses must be handled per client. PasteGuard inverts that: one process speaks the provider's own URL shape, so an OpenAI SDK needs a base_url change and nothing else, and streaming is handled once. The cost of the inversion is that the proxy sees all your prompts and keeps a request log, which is precisely the data you were trying to keep contained. That log is local, but it is a log. If your threat model includes the host running the proxy, a library with no persistence is the smaller surface.

A second alternative is to skip masking entirely and run a local model for everything. PasteGuard's Route Mode is a partial version of that, keeping cloud providers for the non-sensitive majority of traffic.

Maintenance cost, licence, and what to check before adopting

The release cadence visible in the material is three releases in roughly a month, v0.9.1 and v0.9.2 on consecutive days in late July 2026 and v0.9.3 on 25 August 2026. All are 0.9.x, which means the project has not declared a 1.0 stability boundary. Expect configuration and API surface changes between minor versions, and pin the container tag rather than tracking latest in anything you depend on.

The operational surface is a container, a dashboard, a SQLite or Postgres store, and a Python detector process with GLiNER. GLiNER is a model, so there is a model artifact to fetch, host and update, plus whatever compute it needs. That is the recurring cost people underestimate when they read one docker run line. Custom GLiNER models are documented as a configuration path, which implies you can substitute one, but it also implies you may need to.

Licensing is Apache-2.0, which permits commercial use and modification and includes a patent grant. That covers the PasteGuard code. It does not automatically cover the GLiNER model weights or the Python dependencies pulled in by the detector, which carry their own terms, and it says nothing about your obligations to the people whose data you are masking. Check the licences of the model and the detector dependencies separately before you ship this inside a product.

Editorial conclusion

Adopt PasteGuard if you already route model traffic through a base URL you control and want masking applied at that chokepoint rather than inside each application. Do not adopt it if your sensitive data is mostly free-form narrative, since the semantic layer rests on GLiNER alone, or if you need a hardened browser extension today, because the README still labels it experimental. Before rollout, verify three things against your own traffic: what the detector flags on a sample of real prompts, whether your provider's response format is among those whose placeholders get restored, and whether your deployment topology keeps the SQLite or Postgres request log inside your trust boundary.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. sgasser/pasteguard on GitHub
Community notes

Community notes