Self-hosted LLM firewall with on-device GPU threat detection.
JavaScript
1
19 commits
updated Feb 7, 2026

Self-hosted LLM firewall with on-device GPU threat detection.
Analyze every message for prompt injection, jailbreaks, PII leakage, and semantic evasion attacks using a real 21B-parameter model — not regex, not keyword matching.
Quick Start • Connect Clients • Configuration • Deployment • Security
Most LLM security tools rely on pattern matching or cloud-hosted classifiers. PooGuard runs a 21-billion parameter MoE safeguard model (3.6B active) directly on your GPU — every request scored locally, nothing leaves your infrastructure. Deploy it as a drop-in OpenAI-compatible proxy: point SillyTavern, Open WebUI, Chatbox, or any client at PooGuard and every request is analyzed, scored, and logged with zero changes to your setup.
[!NOTE] Requires an NVIDIA GPU with 16 GB+ VRAM (RTX 4080 or better). First run downloads the ~13 GB model — cached in a Docker volume for subsequent starts.
git clone https://github.com/tacos8me/PooGuard.git
cd PooGuard
cp .env.example .env
# Edit .env — set at minimum: HF_TOKEN, JWT_SECRET, DB_PASSWORD
docker compose up
| Service | URL |
|---|---|
| Dashboard | http://localhost:3000 |
| API | http://localhost:3001 |
| Proxy | http://localhost:3001/v1 |
Default login: [email protected] with a randomly generated password (printed to console on first seed, or set ADMIN_PASSWORD env var).
Request ➜ Auth ➜ Extract ➜ Normalize ➜ Classify ➜ Evaluate ➜ Forward ➜ Upstream LLM
| |
Block Response
| |
▼ ▼
Client ◀── Egress Scan
/v1/chat/completions accepts JWT tokens or PooGuard API keys (sk-pg-*). Credentials validated via SHA-256 hash lookup.messages array, including multi-part content.PooGuard exposes an OpenAI-compatible proxy at /v1. Any client that supports a custom base URL works out of the box.
Create an API key: Log in to the dashboard, go to Settings > API Keys, and create a key (sk-pg-<hex>). Copy it immediately — shown only once.
# curl
curl http://localhost:3001/v1/chat/completions \
-H "Authorization: Bearer sk-pg-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "any-model-name",
"messages": [{"role": "user", "content": "Hello!"}]
}'
# Any OAI-compatible client
export OPENAI_BASE_URL=http://your-server:3001/v1
export OPENAI_API_KEY=sk-pg-YOUR_KEY
SillyTavern:
http://your-server:3001/v1sk-pg- API keyOpen WebUI:
http://your-server:3001/v1| Variable | Required | Default | Description |
|---|---|---|---|
HF_TOKEN | Yes | — | HuggingFace token for model download |
JWT_SECRET | Yes | — | Token signing key (min 32 chars) |
DB_PASSWORD | Yes | — | PostgreSQL password |
REDIS_PASSWORD | No | redis-dev-password | Redis authentication password |
MODEL_NAME | No | openai/gpt-oss-safeguard-20b | HuggingFace model name |
SAFEGUARD_MODEL_SIZE | No | 20b | Model variant: 20b or 120b |
MODEL_SERVICE_API_KEY | No | — | Backend-to-model-service auth key |
ALLOWED_ORIGINS | No | localhost:3000,5173 | CORS allowed origins |
Tune detection sensitivity from the dashboard Settings page:
| Preset | Prompt Injection | Jailbreak | PII | Semantic | Use Case |
|---|---|---|---|---|---|
| High Security | 0.40 | 0.40 | 0.50 | 0.28 | Maximize detection, accept more false positives |
| Balanced | 0.70 | 0.70 | 0.70 | 0.42 | Best F1 score (default) |
| Low Friction | 0.90 | 0.90 | 0.90 | 0.50 | Minimize false positives |
[!TIP] The model produces bimodal scores (near 0.0 or 0.8–0.95), so small threshold changes in the middle range have little practical effect. Lower thresholds = more aggressive blocking.
cd backend && npx jest --no-coverage # 449 tests
cd model-service && python -m pytest tests/ -v # 216 tests
cd frontend && npx vitest run # 31 tests
| Suite | Framework | Tests | Coverage |
|---|---|---|---|
| Backend | Jest + Supertest | 449 | Routes, middleware, services, utilities |
| Model Service | pytest | 216 | Inference, normalization, semantic similarity, API |
| Frontend | Vitest | 31 | Components, auth flows, settings |
Benchmarked on RTX 5090 (32 GB) with the 20B model in MXFP4 quantization, 360-example dataset:
| Metric | Latency |
|---|---|
| Mean | 2.6s |
| Median | 2.8s |
| P95 | 3.6s |
| Clean inputs (avg) | 1.9s |
| Threat inputs (avg) | 3.1s |
Early-exit stopping cuts clean-input latency nearly in half — most production traffic is clean. Streaming proxy requests begin forwarding immediately; analysis runs in parallel.
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
Mounts source directories for hot reload — backend with nodemon, frontend with Vite HMR, model service with live main.py mounting. Dev mode also exposes PostgreSQL (5432), Redis (6379), and model-service (8000) for direct access.
# Backend
cd backend && npm install && npm run migrate && npm run dev
# Frontend
cd frontend && npm install && npm run dev
# Model service (requires GPU)
cd model-service && pip install -r requirements.txt
uvicorn main:app --host 0.0.0.0 --port 8000
| Layer | Technology | Purpose |
|---|---|---|
| ML Inference | PyTorch (CUDA 12.8), Transformers | GPU model inference with MXFP4 quantization |
| Embeddings | sentence-transformers | Semantic similarity attack detection |
| Model API | Python 3.12, FastAPI, Uvicorn | Threat classification service |
| Backend | Node.js, Express 4 | REST API, WebSocket, LLM proxy |
| Auth | jsonwebtoken, bcrypt | JWT + SHA-256 hashed API keys |
| Database | PostgreSQL 16, Knex.js | Request logs, config, audit trail, alerts |
| Cache / PubSub | Redis 7 | Rate limiting, cache, real-time event bus |
| Real-time | Socket.IO 4 | WebSocket events to dashboard |
| Frontend | React 18, Vite 5, TailwindCSS 3 | Monitoring dashboard |
| Charts | Recharts 2 | Analytics visualizations |
| Security | Helmet, CORS, CSRF | HTTP hardening |
| Infrastructure | Docker Compose | Multi-service orchestration with GPU passthrough |
Contributions welcome. Please open an issue first to discuss what you'd like to change.
git checkout -b feature/my-change)Self-hosted LLM firewall with on-device GPU threat detection.
JavaScript
1
19 commits
updated Feb 7, 2026

Self-hosted LLM firewall with on-device GPU threat detection.
Analyze every message for prompt injection, jailbreaks, PII leakage, and semantic evasion attacks using a real 21B-parameter model — not regex, not keyword matching.
Quick Start • Connect Clients • Configuration • Deployment • Security
Most LLM security tools rely on pattern matching or cloud-hosted classifiers. PooGuard runs a 21-billion parameter MoE safeguard model (3.6B active) directly on your GPU — every request scored locally, nothing leaves your infrastructure. Deploy it as a drop-in OpenAI-compatible proxy: point SillyTavern, Open WebUI, Chatbox, or any client at PooGuard and every request is analyzed, scored, and logged with zero changes to your setup.
[!NOTE] Requires an NVIDIA GPU with 16 GB+ VRAM (RTX 4080 or better). First run downloads the ~13 GB model — cached in a Docker volume for subsequent starts.
git clone https://github.com/tacos8me/PooGuard.git
cd PooGuard
cp .env.example .env
# Edit .env — set at minimum: HF_TOKEN, JWT_SECRET, DB_PASSWORD
docker compose up
| Service | URL |
|---|---|
| Dashboard | http://localhost:3000 |
| API | http://localhost:3001 |
| Proxy | http://localhost:3001/v1 |
Default login: [email protected] with a randomly generated password (printed to console on first seed, or set ADMIN_PASSWORD env var).
Request ➜ Auth ➜ Extract ➜ Normalize ➜ Classify ➜ Evaluate ➜ Forward ➜ Upstream LLM
| |
Block Response
| |
▼ ▼
Client ◀── Egress Scan
/v1/chat/completions accepts JWT tokens or PooGuard API keys (sk-pg-*). Credentials validated via SHA-256 hash lookup.messages array, including multi-part content.PooGuard exposes an OpenAI-compatible proxy at /v1. Any client that supports a custom base URL works out of the box.
Create an API key: Log in to the dashboard, go to Settings > API Keys, and create a key (sk-pg-<hex>). Copy it immediately — shown only once.
# curl
curl http://localhost:3001/v1/chat/completions \
-H "Authorization: Bearer sk-pg-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "any-model-name",
"messages": [{"role": "user", "content": "Hello!"}]
}'
# Any OAI-compatible client
export OPENAI_BASE_URL=http://your-server:3001/v1
export OPENAI_API_KEY=sk-pg-YOUR_KEY
SillyTavern:
http://your-server:3001/v1sk-pg- API keyOpen WebUI:
http://your-server:3001/v1| Variable | Required | Default | Description |
|---|---|---|---|
HF_TOKEN | Yes | — | HuggingFace token for model download |
JWT_SECRET | Yes | — | Token signing key (min 32 chars) |
DB_PASSWORD | Yes | — | PostgreSQL password |
REDIS_PASSWORD | No | redis-dev-password | Redis authentication password |
MODEL_NAME | No | openai/gpt-oss-safeguard-20b | HuggingFace model name |
SAFEGUARD_MODEL_SIZE | No | 20b | Model variant: 20b or 120b |
MODEL_SERVICE_API_KEY | No | — | Backend-to-model-service auth key |
ALLOWED_ORIGINS | No | localhost:3000,5173 | CORS allowed origins |
Tune detection sensitivity from the dashboard Settings page:
| Preset | Prompt Injection | Jailbreak | PII | Semantic | Use Case |
|---|---|---|---|---|---|
| High Security | 0.40 | 0.40 | 0.50 | 0.28 | Maximize detection, accept more false positives |
| Balanced | 0.70 | 0.70 | 0.70 | 0.42 | Best F1 score (default) |
| Low Friction | 0.90 | 0.90 | 0.90 | 0.50 | Minimize false positives |
[!TIP] The model produces bimodal scores (near 0.0 or 0.8–0.95), so small threshold changes in the middle range have little practical effect. Lower thresholds = more aggressive blocking.
cd backend && npx jest --no-coverage # 449 tests
cd model-service && python -m pytest tests/ -v # 216 tests
cd frontend && npx vitest run # 31 tests
| Suite | Framework | Tests | Coverage |
|---|---|---|---|
| Backend | Jest + Supertest | 449 | Routes, middleware, services, utilities |
| Model Service | pytest | 216 | Inference, normalization, semantic similarity, API |
| Frontend | Vitest | 31 | Components, auth flows, settings |
Benchmarked on RTX 5090 (32 GB) with the 20B model in MXFP4 quantization, 360-example dataset:
| Metric | Latency |
|---|---|
| Mean | 2.6s |
| Median | 2.8s |
| P95 | 3.6s |
| Clean inputs (avg) | 1.9s |
| Threat inputs (avg) | 3.1s |
Early-exit stopping cuts clean-input latency nearly in half — most production traffic is clean. Streaming proxy requests begin forwarding immediately; analysis runs in parallel.
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
Mounts source directories for hot reload — backend with nodemon, frontend with Vite HMR, model service with live main.py mounting. Dev mode also exposes PostgreSQL (5432), Redis (6379), and model-service (8000) for direct access.
# Backend
cd backend && npm install && npm run migrate && npm run dev
# Frontend
cd frontend && npm install && npm run dev
# Model service (requires GPU)
cd model-service && pip install -r requirements.txt
uvicorn main:app --host 0.0.0.0 --port 8000
| Layer | Technology | Purpose |
|---|---|---|
| ML Inference | PyTorch (CUDA 12.8), Transformers | GPU model inference with MXFP4 quantization |
| Embeddings | sentence-transformers | Semantic similarity attack detection |
| Model API | Python 3.12, FastAPI, Uvicorn | Threat classification service |
| Backend | Node.js, Express 4 | REST API, WebSocket, LLM proxy |
| Auth | jsonwebtoken, bcrypt | JWT + SHA-256 hashed API keys |
| Database | PostgreSQL 16, Knex.js | Request logs, config, audit trail, alerts |
| Cache / PubSub | Redis 7 | Rate limiting, cache, real-time event bus |
| Real-time | Socket.IO 4 | WebSocket events to dashboard |
| Frontend | React 18, Vite 5, TailwindCSS 3 | Monitoring dashboard |
| Charts | Recharts 2 | Analytics visualizations |
| Security | Helmet, CORS, CSRF | HTTP hardening |
| Infrastructure | Docker Compose | Multi-service orchestration with GPU passthrough |
Contributions welcome. Please open an issue first to discuss what you'd like to change.
git checkout -b feature/my-change)