- uses: actions/checkout@v4
- name: Test Docker build
- run: docker build -t llm-shield:test .
\ No newline at end of file
+ run: docker build -t pasteguard:test .
\ No newline at end of file
-# LLM-Shield
+# PasteGuard
OpenAI-compatible proxy with two privacy modes: route to local LLM or mask PII for upstream.
- Framework: Hono (with JSX for dashboard)
- Validation: Zod
- Styling: Tailwind CSS v4
-- Database: SQLite (`data/llm-shield.db`)
+- Database: SQLite (`data/pasteguard.db`)
- PII Detection: Microsoft Presidio (Docker)
- Code Style: Biome (see @biome.json)
- `GET /info` - Mode info
- `POST /openai/v1/chat/completions` - Main endpoint
-Response header `X-LLM-Shield-PII-Masked: true` indicates PII was masked.
+Response header `X-PasteGuard-PII-Masked: true` indicates PII was masked.
-# Contributing to LLM-Shield
+# Contributing to PasteGuard
-Thank you for considering contributing to LLM-Shield!
+Thank you for considering contributing to PasteGuard!
## Development Setup
-# π‘οΈ LLM-Shield
+# π‘οΈ PasteGuard
-[](https://github.com/sgasser/llm-shield/actions/workflows/ci.yml)
+[](https://github.com/sgasser/pasteguard/actions/workflows/ci.yml)
[](LICENSE)
Privacy proxy for LLMs. Masks personal data before sending to your provider (OpenAI, Azure, etc.), or routes sensitive requests to local LLM.
-<img src="docs/dashboard.png" width="100%" alt="LLM-Shield Dashboard">
+<img src="docs/dashboard.png" width="100%" alt="PasteGuard Dashboard">
## Mask Mode (Default)
### Docker (recommended)
```bash
-git clone https://github.com/sgasser/llm-shield.git
-cd llm-shield
+git clone https://github.com/sgasser/pasteguard.git
+cd pasteguard
cp config.example.yaml config.yaml
# Option 1: English only (default, ~1.5GB)
### Local Development
```bash
-git clone https://github.com/sgasser/llm-shield.git
-cd llm-shield
+git clone https://github.com/sgasser/pasteguard.git
+cd pasteguard
bun install
cp config.example.yaml config.yaml
- Text language is auto-detected for each request
- If detected language is not installed, falls back to `fallback_language` (default: `en`)
- Dashboard shows fallback as `FRβEN` when French text is detected but only English is installed
-- Response header `X-LLM-Shield-Language-Fallback: true` indicates fallback was used
+- Response header `X-PasteGuard-Language-Fallback: true` indicates fallback was used
Update `config.yaml` to match your installed languages:
```yaml
logging:
- database: ./data/llm-shield.db
+ database: ./data/pasteguard.db
retention_days: 30 # 0 = keep forever
log_content: false # Log full request/response
log_masked_content: true # Log masked content for dashboard
| Header | Value |
|--------|-------|
| `X-Request-ID` | Request identifier (forwarded or generated) |
-| `X-LLM-Shield-Mode` | `route` / `mask` |
-| `X-LLM-Shield-PII-Detected` | `true` / `false` |
-| `X-LLM-Shield-PII-Masked` | `true` / `false` (mask mode) |
-| `X-LLM-Shield-Provider` | `upstream` / `local` |
-| `X-LLM-Shield-Language` | Detected language code |
-| `X-LLM-Shield-Language-Fallback` | `true` if fallback was used |
+| `X-PasteGuard-Mode` | `route` / `mask` |
+| `X-PasteGuard-PII-Detected` | `true` / `false` |
+| `X-PasteGuard-PII-Masked` | `true` / `false` (mask mode) |
+| `X-PasteGuard-Provider` | `upstream` / `local` |
+| `X-PasteGuard-Language` | Detected language code |
+| `X-PasteGuard-Language-Fallback` | `true` if fallback was used |
## Development
"configVersion": 1,
"workspaces": {
"": {
- "name": "llm-shield",
+ "name": "pasteguard",
"dependencies": {
"@hono/zod-validator": "^0.7.6",
"eld": "^2.0.1",
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
- "eld": ["eld@2.0.1", "", {}, "sha512-Lo+M5M7IL/N3MSXMbnfBrdsn+qu0rScPyOA/POvxKU7HsLEOfFOJuEBC96vmYxMJShxXtH+wnWVOhgu+rf7u9A=="],
+ "eld": ["eld@2.0.2", "", {}, "sha512-8ECUdQkhChI68V4n2j1zLsUKRGtOtBm3hA2RHrA05I9Y+BU7iLgClZnpGdEUpmAw3xKyVHQcSzuBVDkjCkP4ag=="],
"enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="],
-# LLM-Shield Configuration
+# PasteGuard Configuration
# Copy this file to config.yaml and adjust the values
# Privacy mode: "mask" or "route"
# Logging settings
logging:
# SQLite database for request logs
- database: ./data/llm-shield.db
+ database: ./data/pasteguard.db
# Log retention in days (0 = keep forever)
retention_days: 30
services:
- llm-shield:
+ pasteguard:
build: .
ports:
- "3000:3000"
{
- "name": "llm-shield",
+ "name": "pasteguard",
"version": "0.1.0",
- "description": "Intelligent privacy-aware routing for LLMs - OpenAI-compatible proxy that routes requests based on PII detection",
+ "description": "Guard your paste - Privacy-aware LLM proxy that masks PII before sending to cloud LLMs",
"type": "module",
"main": "src/index.ts",
"scripts": {
"license": "Apache-2.0",
"repository": {
"type": "git",
- "url": "https://github.com/sgasser/llm-shield"
+ "url": "https://github.com/sgasser/pasteguard"
}
}
-# LLM-Shield Presidio Analyzer
+# PasteGuard Presidio Analyzer
# Multi-language PII detection with configurable language support
#
# Build with specific languages:
-# LLM-Shield Language Registry
+# PasteGuard Language Registry
# All 24 spaCy languages with trained pipelines
#
# Usage: Set LANGUAGES build arg to select which to install
});
const LoggingSchema = z.object({
- database: z.string().default("./data/llm-shield.db"),
+ database: z.string().default("./data/pasteguard.db"),
retention_days: z.coerce.number().int().min(0).default(30),
log_content: z.boolean().default(false),
log_masked_content: z.boolean().default(true),
console.log(`
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-β LLM-Shield β
-β Intelligent privacy-aware LLM proxy β
+β PasteGuard β
+β Guard your paste - Privacy-aware LLM proxy β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Server: http://${host}:${port}
basicAuth({
username: config.dashboard.auth.username,
password: config.dashboard.auth.password,
- realm: "LLM-Shield Dashboard",
+ realm: "PasteGuard Dashboard",
}),
);
}
expect(res.status).toBe(200);
const body = (await res.json()) as Record<string, unknown>;
- expect(body.name).toBe("LLM-Shield");
+ expect(body.name).toBe("PasteGuard");
expect(body.version).toBe("0.1.0");
expect(body.mode).toBeDefined();
expect(body.providers).toBeDefined();
const languageValidation = detector.getLanguageValidation();
const info: Record<string, unknown> = {
- name: "LLM-Shield",
+ name: "PasteGuard",
version: pkg.version,
- description: "Intelligent privacy-aware LLM proxy",
+ description: "Guard your paste - Privacy-aware LLM proxy",
mode: config.mode,
providers: {
upstream: {
}
/**
- * Set X-LLM-Shield response headers
+ * Set X-PasteGuard response headers
*/
function setShieldHeaders(c: Context, decision: RoutingDecision) {
- c.header("X-LLM-Shield-Mode", decision.mode);
- c.header("X-LLM-Shield-Provider", decision.provider);
- c.header("X-LLM-Shield-PII-Detected", decision.piiResult.hasPII.toString());
- c.header("X-LLM-Shield-Language", decision.piiResult.language);
+ c.header("X-PasteGuard-Mode", decision.mode);
+ c.header("X-PasteGuard-Provider", decision.provider);
+ c.header("X-PasteGuard-PII-Detected", decision.piiResult.hasPII.toString());
+ c.header("X-PasteGuard-Language", decision.piiResult.language);
if (decision.piiResult.languageFallback) {
- c.header("X-LLM-Shield-Language-Fallback", "true");
+ c.header("X-PasteGuard-Language-Fallback", "true");
}
if (decision.mode === "mask") {
- c.header("X-LLM-Shield-PII-Masked", decision.piiResult.hasPII.toString());
+ c.header("X-PasteGuard-PII-Masked", decision.piiResult.hasPII.toString());
}
}
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>LLM-Shield Dashboard</title>
+ <title>PasteGuard Dashboard</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
π‘οΈ
</div>
<div class="text-xl font-bold tracking-tight text-text-primary">
- LLM<span class="text-amber">Shield</span>
+ Paste<span class="text-amber">Guard</span>
</div>
</div>
<div class="flex items-center gap-4">