# PasteGuard: A Local-First Privacy Proxy for Browser Chat, AI APIs and Coding Agents

> PasteGuard is a TypeScript proxy that masks PII and secrets before requests reach OpenAI, Anthropic, Gemini, Codex or Claude Code, then restores supported placeholders in the response. It is aimed at teams that cannot paste raw customer or production data into a model provider.

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

- Repository: https://github.com/sgasser/pasteguard
- Website: https://pasteguard.com
- Stars: 758 · Forks: 40
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/sgasser-pasteguard

## The problem PasteGuard targets: raw context leaving your machine

Most teams working under strict privacy rules face the same four options: stop using cloud AI for sensitive work, redact by hand, switch to a local model even when a cloud provider would give better results, or write one-off masking code inside every application. PasteGuard is positioned as a fifth option: a control point that sits between your tool and the provider.

The README frames the audience narrowly. It is for teams that "cannot send raw client data, customer records, logs, credentials, or production details directly to model providers." That is a compliance-shaped constraint, not a general preference for privacy. The project is explicit that it "can support regulated workflows, but it does not replace your legal, security, or compliance program," which is the honest framing: the tool is one control, not an attestation.

The three surfaces it covers are browser chat (ChatGPT, Claude, Gemini), apps and SDKs that call provider APIs, and coding agents such as Codex, Claude Code, Cursor, Windsurf and Copilot. The browser extension is described as experimental, so treat that surface as the least settled of the three.

## How the masking pipeline works across three surfaces

For applications, the mechanism is a base URL swap. You point your client at PasteGuard instead of the provider. PasteGuard masks the request, forwards it upstream, and restores supported placeholders in the response. The README gives the mapping directly: OpenAI goes to `http://localhost:3000/openai/v1` instead of `https://api.openai.com/v1`, Anthropic to `http://localhost:3000/anthropic` instead of `https://api.anthropic.com`, and the Codex CLI to `http://localhost:3000/codex` instead of `https://chatgpt.com/backend-api/codex`.

Detection is split by value type. Structured values (credit cards, IBANs, EU VAT numbers, IP addresses, API keys) are handled with checksums and format checks. Names and locations go through a semantic backend, and the README states that GLiNER is currently the only backend. That is a meaningful architectural constraint: the semantic path is a Python component, not the TypeScript proxy, which is why the repository carries a separate `detector/` directory and why docker-compose defines a `detector` service that builds the `detector` target of the same `docker/Dockerfile`.

There are two operating modes. Mask Mode replaces values with placeholders and restores supported ones on the way back. Route Mode instead sends any request containing sensitive data to a local LLM such as Ollama, vLLM or llama.cpp, while clean requests can still go to the configured cloud provider. Route Mode is the stronger privacy position because nothing sensitive leaves at all, but it only works if you already run a local model good enough for the task.

The stack is Bun, Hono, GLiNER with python-stdnum, and SQLite or Postgres for storage. Streaming responses are handled: the README says detection and masking happen in real time "including streaming responses," which matters because streaming is where naive redaction implementations break.

## Installing PasteGuard with Docker and making a first masked request

The README's quick start is a single container run. The published image bundles the proxy and the PII detector, so there is no second process to start for a first look.

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

After that, `localhost:3000` serves the dashboard, which logs every request with masking details: what was detected, what was masked, and what reached the provider. That dashboard is the fastest way to confirm the pipeline is actually doing something before you wire it into an application.

The next step is pointing a client at it. The README's example uses the OpenAI Python SDK with only the base URL changed:

```python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:3000/openai/v1")
```

According to the README, both `client.chat.completions.create(...)` and `client.responses.create(...)` pass through the privacy pipeline. Send a request containing something obviously sensitive, then open the dashboard and check whether it appears in the masked column rather than the forwarded one.

For anything beyond a trial, the README points at the installation docs for custom config, persistent logs, Docker Compose and custom GLiNER models. The Compose file in the repository mounts `./config.yaml` read-only into the container and `./data` for persistence, and reads an optional `.env` via `env_file`. The port is parameterised as `${PASTEGUARD_PORT:-3000}:3000`. Note that the `detector` service in that file is marked `profiles: ["dev"]` and exists only for running the proxy from source with `bun run dev` against a containerised detector on port 5002.

## Where PasteGuard is the wrong tool

The clearest limitation is stated in the README itself: GLiNER is currently the only semantic backend. If your sensitive data is mostly free-text names, places and organisation references rather than structured identifiers, your detection quality depends entirely on that one model, and swapping it means going to the custom GLiNER model documentation. There is no second semantic option to fall back on.

Restoration is also scoped. The README says "supported" placeholders are restored in the response. It does not enumerate which placeholder types survive a round trip through each provider, and it does not document what happens when a model paraphrases, splits or reformats a placeholder. That is the failure mode worth testing yourself: a model that rewrites `[PERSON_1]` into something else leaves you with a response you have to reconcile by hand.

Route Mode has a different cost. Sending sensitive requests to Ollama, vLLM or llama.cpp keeps data local, but it also means the model answering your hardest questions is your local one. If the whole reason you use a cloud provider is capability on sensitive material, Route Mode does not solve that; it just makes the trade-off explicit.

Finally, PasteGuard is a proxy. It sees the request body. If your threat model includes the host running PasteGuard, the dashboard logs, or the SQLite or Postgres database behind it, the proxy becomes a new place where sensitive data accumulates. The README does not document log retention or redaction of the dashboard store, so that is a question for your own deployment.

## PasteGuard compared with building masking into each application

The realistic alternative is not another proxy. It is the option the README lists as the status quo: build one-off masking code inside every app.

The difference is where the logic lives and who maintains it. In-app masking means each service owns its own regexes, its own placeholder scheme and its own restoration step, and each one has to be updated when a provider changes a response shape. PasteGuard centralises that into one process with one configuration file and one dashboard, and it covers surfaces that in-app code cannot reach at all, such as ChatGPT in a browser or a coding agent reading your repository.

The cost of centralising is that everything now depends on one component being up and correctly configured. An in-app regex fails inside one service; a misconfigured proxy fails across every client pointed at it. The Compose file's `restart: unless-stopped` is the only resilience the repository's own configuration offers, and the README does not document rollback or a bypass path for when the proxy misbehaves.

A second alternative is simply not sending the data: use a local model for the sensitive work and a cloud provider for everything else. That is a policy answer rather than a tooling answer, and PasteGuard's Route Mode is essentially an automated version of it.

## Maintenance, releases and the Apache-2.0 licence

The repository is not archived, and the last push was on 2026-08-25. Releases have been frequent through mid-2026: v0.9.1 on 2026-07-30, v0.9.2 on 2026-07-31, and v0.9.3 on 2026-08-25. The version in `package.json` matches v0.9.3. The 0.9.x numbering is worth noting for planning: the project has not reached 1.0, and the browser extension is described as experimental, so interface and configuration changes between minor versions are a real possibility.

Upgrade cost depends on how you run it. Using the published image means pulling a new tag. Running from source means Bun, plus the Python detector with GLiNER and python-stdnum, plus a database. The `package.json` scripts give the local workflow: `bun run dev` for hot reload, `bun test`, `bun run typecheck`, and `bun run benchmark:accuracy`, which runs `benchmarks/pii-accuracy/run.ts`. That benchmark script is the right thing to run before and after an upgrade, since it is the only accuracy signal the repository exposes.

On licensing, PasteGuard is Apache-2.0, a permissive licence that allows commercial use and modification with the usual notice and patent terms. This is not legal advice. The practical implication for a privacy tool is that self-hosting and internal modification are unambiguously permitted, and the README says you can "run it locally or self-host it in your own infrastructure." If you fork the detector, keep the licence and notice files intact.

## Conclusion

Adopt PasteGuard if your workload involves pasting customer records, logs or credentials into a cloud model and you want a single control point rather than masking code inside every app. Skip it if you already route sensitive work to a local model, or if you need a guarantee about which categories are detected, because the README does not publish accuracy figures and GLiNER is the only semantic backend today. Before rolling it out, run the benchmark script against your own text, confirm the placeholder restoration behaviour for your provider's response format, and decide whether you need config.yaml and a persistent data volume rather than the default container command.

## FAQ

### How do I install and run PasteGuard locally?

The README's quick start is `docker run --rm -p 3000:3000 ghcr.io/sgasser/pasteguard:latest`. The published image bundles the proxy and the PII detector, and the dashboard is then available on localhost:3000.

### Does PasteGuard work with coding agents like Codex and Claude Code?

Yes. The README lists Codex, Claude Code, Cursor, Windsurf and Copilot as supported coding agents, and gives the Codex CLI mapping `http://localhost:3000/codex` in place of `https://chatgpt.com/backend-api/codex`.

### What is the difference between Mask Mode and Route Mode in PasteGuard?

Mask Mode replaces PII and secrets with placeholders before the request goes upstream and restores supported placeholders on the way back. Route Mode instead sends requests containing sensitive data to a local LLM such as Ollama, vLLM or llama.cpp, while requests without sensitive data can still go to the cloud provider.

### Which semantic detection backend does PasteGuard use?

GLiNER is currently the only backend, and the README points to the Semantic Backends documentation for details. Structured values such as credit cards, IBANs and API keys are handled separately with checksums and format checks.

## Sources

- [License: Apache-2.0](https://github.com/sgasser/pasteguard/blob/main/LICENSE)
- [Project website](https://pasteguard.com)
- [README](https://github.com/sgasser/pasteguard/blob/main/README.md)
- [Releases](https://github.com/sgasser/pasteguard/releases)
- [sgasser/pasteguard on GitHub](https://github.com/sgasser/pasteguard)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sgasser-pasteguard
