Proxy Gateway¶
Deploy OxideShield™ as a transparent HTTP proxy between your application and LLM APIs. The proxy intercepts all traffic, applies security guards, and provides enterprise features like rate limiting, user tracking, and real-time alerts.
License Tiers
Professional (£149/month): Core proxy gateway - ideal for Molt and chat bot deployments. Includes request/response interception, all guards, and basic configuration.
Enterprise (POE): Advanced features - webhook alerts (Slack, Discord), rate limiting, streaming guards, and user tracking with strike system.
Architecture¶
Quick Start¶
# Start proxy with Anthropic upstream
oxideshield proxy \
--listen 0.0.0.0:8080 \
--upstream anthropic=https://api.anthropic.com \
--guards PatternGuard,PIIGuard
# With full configuration file
oxideshield proxy --config proxy.yaml
# Validate configuration
oxideshield proxy --validate --config proxy.yaml
# Print example config
oxideshield proxy --example-config
Configuration Reference¶
Complete Configuration¶
# proxy.yaml - Complete reference configuration
proxy:
# Network settings
listen: "0.0.0.0:8080"
# TLS configuration (optional)
tls:
enabled: false
cert_path: "/etc/ssl/certs/oxideshield.crt"
key_path: "/etc/ssl/private/oxideshield.key"
# Upstream LLM APIs
upstreams:
anthropic:
url: "https://api.anthropic.com"
timeout_ms: 60000
retry_attempts: 2
retry_delay_ms: 1000
openai:
url: "https://api.openai.com"
timeout_ms: 30000
# Request routing
routing:
- path: "/v1/messages"
upstream: anthropic
- path: "/v1/chat/completions"
upstream: openai
- path: "/*"
upstream: anthropic # Default
# Security guards
guards:
input:
- name: length
type: length
config:
max_chars: 10000
max_tokens: 4000
action: block
- name: encoding
type: encoding
config:
detect_invisible: true
detect_homoglyphs: true
normalize: true
action: sanitize
- name: pattern
type: pattern
config:
categories:
- prompt_injection
- jailbreak
- system_prompt_leak
action: block
- name: pii
type: pii
config:
redaction: mask
categories:
- email
- phone
- ssn
- credit_card
action: sanitize
output:
- name: pii_output
type: pii
config:
redaction: mask
action: sanitize
- name: toxicity
type: toxicity
config:
threshold: 0.7
action: block
# Guard pipeline settings
pipeline:
strategy: fail_fast # fail_fast, all, or custom
on_error: block # block or allow
# Streaming response handling
streaming:
strategy: periodic
eval_interval_chars: 500
eval_interval_tokens: 100
max_eval_interval_ms: 2000
early_termination: true
max_buffer_chars: 10000
# Rate limiting
rate_limit:
enabled: true
requests_per_minute: 60
requests_per_hour: 1000
tokens_per_hour: 100000
burst: 10
limit_by: ip_address
whitelist: []
custom_limits: {}
response:
status_code: 429
retry_after_seconds: 60
message: "Rate limit exceeded"
# User tracking
tracking:
enabled: true
max_strikes: 3
strike_window_seconds: 3600
block_duration_seconds: 86400
track_by: ip_address
strike_actions:
- Block
blocklist: []
allowlist: []
# Webhook alerts
alerts:
destinations: []
events:
- block
- high_severity
rate_limit_per_minute: 60
include_request_details: false
retry:
max_retries: 3
initial_backoff_ms: 1000
max_backoff_ms: 30000
# Metrics
metrics:
enabled: true
endpoint: "/metrics"
# Health checks
health:
enabled: true
endpoint: "/health"
Streaming Protection¶
The proxy handles streaming SSE responses with real-time guard evaluation.
Streaming Strategies¶
| Strategy | Description | Latency | Security |
|---|---|---|---|
end_only |
Evaluate only after stream completes | Lowest | Basic |
periodic |
Evaluate at intervals (chars/time) | Low | Good |
sentence_boundary |
Evaluate at sentence ends | Medium | Better |
continuous |
Evaluate every chunk | Highest | Maximum |
Configuration¶
streaming:
# Evaluation strategy
strategy: periodic
# Trigger evaluation every N characters
eval_interval_chars: 500
# Trigger evaluation every N estimated tokens
eval_interval_tokens: 100
# Maximum time between evaluations (ms)
max_eval_interval_ms: 2000
# Terminate stream immediately on threat detection
early_termination: true
# Force evaluation if buffer exceeds this size
max_buffer_chars: 10000
How Streaming Evaluation Works¶
Early Termination Response¶
When a threat is detected mid-stream, the proxy sends an SSE error event:
event: error
data: {"type":"security_violation","guard":"pii","message":"Potential credential leak detected","request_id":"req-123"}
Rate Limiting¶
Protect against abuse and control costs with per-client rate limiting.
Configuration¶
rate_limit:
enabled: true
# Request limits
requests_per_minute: 60
requests_per_hour: 1000
# Token limits (estimated from request size)
tokens_per_hour: 100000
# Burst allowance for short spikes
burst: 10
# What to rate limit by
limit_by: ip_address # ip_address, api_key, header, combined
# Clients that bypass rate limiting
whitelist:
- "admin-api-key"
- "192.168.1.100"
# Custom limits for specific clients
custom_limits:
"premium-api-key":
requests_per_minute: 200
requests_per_hour: 5000
tokens_per_hour: 500000
# Response configuration
response:
status_code: 429
retry_after_seconds: 60
message: "Rate limit exceeded. Please slow down."
Rate Limit Keys¶
| Key | Description | Example |
|---|---|---|
ip_address |
Client IP address | 192.168.1.1 |
api_key |
API key from Authorization header | sk-abc123 |
header |
Custom header value | X-Client-ID: client1 |
combined |
IP + API key | 192.168.1.1:sk-abc123 |
Rate Limit Response¶
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
"error": {
"type": "rate_limit_exceeded",
"message": "Rate limit exceeded: 60 requests/minute",
"retry_after": 60
}
}
Checking Rate Limit Status¶
Response:
{
"requests_minute": 45,
"requests_minute_limit": 60,
"requests_hour": 500,
"requests_hour_limit": 1000,
"tokens_hour": 75000,
"tokens_hour_limit": 100000,
"burst_available": 8
}
User Tracking¶
Track user behavior and automatically block repeat offenders.
Strike System¶
Users accumulate strikes for security violations. After reaching the maximum, they're automatically blocked.
tracking:
enabled: true
# Maximum strikes before block
max_strikes: 3
# Time window for counting strikes (seconds)
strike_window_seconds: 3600 # 1 hour
# How long to block after max strikes
block_duration_seconds: 86400 # 24 hours
# What to track by
track_by: ip_address # ip_address, user_id, channel, channel_user, api_key
# Actions that count as strikes
strike_actions:
- Block
# Permanently blocked users
blocklist:
- "192.168.1.50"
- "bad-api-key"
# Users that are never tracked/blocked
allowlist:
- "admin-key"
- "trusted-ip"
Tracking Keys¶
| Key | Format | Use Case |
|---|---|---|
ip_address |
192.168.1.1 |
Web applications |
user_id |
user_123 |
Authenticated apps |
channel |
discord |
Multi-platform bots |
channel_user |
discord:user_123 |
Chat bots |
api_key |
sk-abc123 |
API consumers |
User Stats API¶
Response:
{
"key": "user_123",
"strikes": 2,
"max_strikes": 3,
"blocked": false,
"first_seen": 3600,
"last_activity": 120,
"total_requests": 150,
"blocked_requests": 5,
"triggered_guards": {
"pattern": 3,
"pii": 2
}
}
Management APIs¶
# Get all blocked users
curl http://proxy:8080/_oxideshield/tracking/blocked
# Get top offenders
curl http://proxy:8080/_oxideshield/tracking/top-offenders?limit=10
# Manually block a user
curl -X POST http://proxy:8080/_oxideshield/tracking/user_123/block \
-d '{"duration_seconds": 86400}'
# Unblock a user
curl -X POST http://proxy:8080/_oxideshield/tracking/user_123/unblock
Webhook Alerts¶
Receive real-time notifications when security events occur.
Supported Destinations¶
Slack¶
alerts:
destinations:
- type: slack
webhook_url: "https://hooks.slack.com/services/T00/B00/XXX"
channel: "#security-alerts" # Optional override
username: "OxideShield™" # Optional
icon_emoji: ":shield:" # Optional
Slack alert format:
🚨 Security Alert
━━━━━━━━━━━━━━━━━
Guard: pattern
Action: Block
Severity: high
Request ID: req-abc123
━━━━━━━━━━━━━━━━━
Reason: Prompt injection detected
Discord¶
Discord embeds with color-coded severity: - Critical: Red (#FF0000) - High: Orange (#FF8C00) - Medium: Gold (#FFD700) - Low: Turquoise (#00CED1)
Generic Webhook¶
alerts:
destinations:
- type: webhook
url: "https://your-siem.example.com/api/events"
method: POST # POST or PUT
headers:
Authorization: "Bearer ${SIEM_TOKEN}"
Content-Type: "application/json"
Webhook payload:
{
"timestamp": "2024-01-15T10:30:00Z",
"request_id": "req-abc123",
"guard": "pattern",
"action": "Block",
"reason": "Prompt injection detected",
"severity": "high",
"channel": "discord",
"user_id": "user_123",
"context": {}
}
Alert Events¶
| Event | Description |
|---|---|
block |
Any blocked request |
high_severity |
High severity detections |
critical |
Critical severity detections |
pii_detected |
PII found in request/response |
jailbreak |
Jailbreak attempt detected |
rate_limit_exceeded |
Rate limit hit |
all |
All events (for debugging) |
Retry Configuration¶
alerts:
retry:
max_retries: 3
initial_backoff_ms: 1000 # Start at 1 second
max_backoff_ms: 30000 # Cap at 30 seconds
Retry uses exponential backoff: 1s -> 2s -> 4s -> ... -> 30s (max)
API Endpoints¶
| Endpoint | Method | Description |
|---|---|---|
/* |
* | Proxy to upstream |
/health |
GET | Health check |
/metrics |
GET | Prometheus metrics |
/_oxideshield/config |
GET | Current configuration |
/_oxideshield/rate-limit/{key} |
GET | Rate limit status |
/_oxideshield/tracking/{key} |
GET | User tracking stats |
/_oxideshield/tracking/{key}/block |
POST | Block user |
/_oxideshield/tracking/{key}/unblock |
POST | Unblock user |
/_oxideshield/tracking/blocked |
GET | List blocked users |
/_oxideshield/tracking/top-offenders |
GET | Top offenders |
Deployment¶
Docker¶
# docker-compose.yml
version: '3.8'
services:
oxideshield:
image: oxideshield/proxy:latest
ports:
- "8080:8080"
environment:
- OXIDESHIELD_PROXY_LISTEN=0.0.0.0:8080
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL}
volumes:
- ./proxy.yaml:/etc/oxideshield/config.yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
Kubernetes¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: oxideshield-proxy
spec:
replicas: 3
selector:
matchLabels:
app: oxideshield-proxy
template:
metadata:
labels:
app: oxideshield-proxy
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
containers:
- name: proxy
image: oxideshield/proxy:latest
ports:
- containerPort: 8080
env:
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: llm-secrets
key: anthropic-api-key
volumeMounts:
- name: config
mountPath: /etc/oxideshield
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: config
configMap:
name: oxideshield-config
---
apiVersion: v1
kind: Service
metadata:
name: oxideshield-proxy
spec:
selector:
app: oxideshield-proxy
ports:
- port: 80
targetPort: 8080
---
apiVersion: v1
kind: ConfigMap
metadata:
name: oxideshield-config
data:
config.yaml: |
proxy:
listen: "0.0.0.0:8080"
upstreams:
anthropic:
url: "https://api.anthropic.com"
# ... rest of config
AWS ECS¶
{
"family": "oxideshield-proxy",
"containerDefinitions": [
{
"name": "proxy",
"image": "oxideshield/proxy:latest",
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"environment": [
{
"name": "OXIDESHIELD_PROXY_LISTEN",
"value": "0.0.0.0:8080"
}
],
"secrets": [
{
"name": "ANTHROPIC_API_KEY",
"valueFrom": "arn:aws:secretsmanager:..."
}
],
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3
}
}
]
}
Monitoring¶
Prometheus Metrics¶
# Request metrics
oxideshield_requests_total{guard="pattern",action="block"} 150
oxideshield_requests_total{guard="pii",action="sanitize"} 2341
# Latency metrics
oxideshield_guard_duration_seconds_bucket{guard="pattern",le="0.001"} 9500
oxideshield_guard_duration_seconds_bucket{guard="pattern",le="0.01"} 9800
# Rate limiting
oxideshield_rate_limit_exceeded_total{key_type="ip_address"} 45
# User tracking
oxideshield_users_blocked_total 12
oxideshield_strikes_recorded_total{guard="pattern"} 89
# Streaming
oxideshield_streams_terminated_total{reason="pii_detected"} 5
oxideshield_stream_chunks_processed_total 125000
# Alerts
oxideshield_alerts_sent_total{destination="slack",status="success"} 150
oxideshield_alerts_sent_total{destination="slack",status="failure"} 2
Grafana Dashboard¶
Import the OxideShield™ dashboard from oxideshield.ai/downloads.
Key panels: - Requests per second by guard/action - P50/P95/P99 latency - Rate limit utilization - Blocked users over time - Alert delivery status
Log Output¶
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "info",
"request_id": "req-abc123",
"guard": "pattern",
"action": "block",
"reason": "Prompt injection detected",
"duration_ms": 2,
"user_key": "192.168.1.1"
}
Security Best Practices¶
1. Enable All Layers¶
rate_limit:
enabled: true
tracking:
enabled: true
alerts:
destinations:
- type: slack
webhook_url: "..."
2. Defense in Depth¶
guards:
input:
- length # Fast rejection
- encoding # Normalization
- pattern # Known attacks
- semantic # Novel attacks
- pii # Data protection
3. Fail Secure¶
4. Monitor Everything¶
5. Regular Updates¶
Troubleshooting¶
Proxy Not Starting¶
# Check port availability
lsof -i :8080
# Run with debug logging
oxideshield proxy --config proxy.yaml --log-level debug
Connection Refused to Upstream¶
# Test upstream connectivity
curl -I https://api.anthropic.com/v1/messages
# Check TLS certificates
openssl s_client -connect api.anthropic.com:443
High Latency¶
# Check guard latency
curl http://proxy:8080/metrics | grep duration
# Consider switching to fail_fast
pipeline:
strategy: fail_fast
False Positives¶
guards:
input:
- name: pattern
config:
confidence_threshold: 0.9 # Increase threshold
exclude_patterns:
- "legitimate_pattern"
Next Steps¶
- Chat Bots & Personal AI - Securing Molt and similar bots
- Multi-Layer Defense - Guard orchestration
- Pattern Guard - Attack pattern configuration
- Benchmarks - Performance characteristics