You hold the keys. AI keeps the cheese.
ALAP · AI Large-Language-Model Auto Pilot
Self-hosted, lightweight, and high-concurrency intelligent WAF.
Let AI take the helm so you can focus where it matters.
- Core Mechanism
- Features
- Request Processing Pipeline
- Paranoia Levels
- Deployment
- Quick Start
- Management Interfaces
- Configuration Reference
- Tech Stack
- Development & Testing
- Corpus Governance
- Documentation
- License
Traditional regex-based WAFs rely on large signature rule sets that require high maintenance and remain susceptible to false positives or evasion techniques. Conversely, invoking LLMs synchronously on every incoming request introduces substantial latency.
CheeseWAF uses a decoupled pipeline:
- Inline Mitigation (Data Plane): An in-process semantic engine decodes parameters and performs Abstract Syntax Tree (AST) lexical analysis to block deterministic exploits in sub-millisecond time.
- Asynchronous Review (ALAP Engine): With ALAP (AI Large-Language-Model Auto Pilot), ambiguous, borderline, or embedded payloads are dispatched to a background review queue for deeper LLM inspection after responses are served, providing autonomous oversight without adding proxy latency.
- Dynamic Rule Synthesis: High-confidence malicious findings (
highorcritical) generated by the model can be automatically promoted into persistent IP, fingerprint, or signature rules applied to the data plane.
The entire system ships as a standalone binary with embedded SQLite storage, an integrated Web console, a terminal TUI tool, and a RESTful administration API.
- Semantic Analysis: Identifies SQL injection, XSS, and command injection attacks using multi-stage decoding and AST parsing instead of rigid regex patterns.
- ALAP Asynchronous Auditing: Works with any OpenAI-compatible API or local LLM gateway in background worker queues without adding latency to live HTTP traffic.
- 0–5 Paranoia Levels: Per-site sensitivity controls that differentiate between isolated attack payloads and patterns embedded inside long text fields, with support for temporary elevation windows (
promote_seconds). - Access Control & Bot Mitigation: Built-in IP allow/deny lists, GeoIP blocking, client soft fingerprinting, slider CAPTCHA challenges, token-bucket rate limiting, and waiting rooms.
- Unified Tri-Interface Management: Responsive Web UI (desktop and mobile), interactive terminal interface (
waf-cli), and RESTful API backed by a single RBAC and audit logging core. - Zero External Dependencies: Written in pure Go with an embedded CGO-free SQLite database (
modernc.org/sqlite).
Solid lines denote the inline millisecond data plane; dashed lines represent post-response asynchronous ALAP auditing and rule sync:
flowchart TB
Client[Client Request] --> Ingress[HTTP / HTTPS / HTTP3 Listener]
Ingress --> IP{IP / Geo / Fingerprint Filter}
IP -->|Matched Blocklist| Block[Block & Return Security Response]
IP -->|Pass| Bot{Bot Defense / Rate Limit / Queue}
Bot -->|Threshold Exceeded| Challenge[CAPTCHA Challenge / Queue]
Challenge -->|Verified| Sem
Bot -->|Pass| Sem[Semantic Analyzer Engine]
Sem --> Shape{Payload Shape & Level Check}
Shape -->|Isolated Attack Level 2-5| Block
Shape -->|Embedded Payload Level 5| Block
Shape -->|Embedded Payload Level 2-4| Pass[Pass to Origin & Async Enqueue]
Shape -->|Clean Traffic| Origin[Forward to Upstream Origin]
Pass --> Origin
Pass -.->|Async Enqueue| Queue[ALAP Review Queue]
Sem -.->|Level 5 Blocked Sample| Queue
Queue --> LLM[Invoke Configured LLM]
LLM --> Review{Threat Review Decision}
Review -->|High / Critical| Rule[Auto-Generate Persistent Rules]
Review -->|Low Risk / FP| Dismiss[Archive or Add to Allowlist]
Rule -.->|Dynamic Rule Hot-Sync| IP
| Plane | Default Address | Description |
|---|---|---|
| Data Plane | http://127.0.0.1:8080 |
Ingress listener for incoming Web traffic and reverse proxying |
| Admin Plane | http://127.0.0.1:9443 |
Web UI, RESTful API, and setup wizard (https:// in Docker) |
| Cluster Plane | http://127.0.0.1:9444 |
Node interconnect and state synchronization in cluster mode |
The paranoia level is configured per site via waf.paranoia_level (valid values: 0–5, default: 3).
Two independent knobs.
waf.paranoia_level(0–5) drives the semantic engine itself — how strictly it judges payload shapes. The proxy's block/challenge thresholds come from a separate setting,protection_policy.web_attack(off/low/smart/high/strict, defaultsmart). They are configured independently: raisingparanoia_levelmakes the engine more sensitive, whileweb_attackdecides what happens to a detection (severity/confidence gates, aggregate risk score, and the fail-mode when the 100 ms detection budget runs out).In log metadata and the console,
waf_policy_decision.paranoia_levelreports the site's configured level (0–5) andwaf_policy_decision.policy_tierreports theweb_attackstrategy ordinal (0–4). They are deliberately separate fields — do not read one as the other.
The analyzer inspects individual decoded parameter values (paths and parameter names remain visible) and categorizes detected attack signatures into two structural shapes:
- Isolated Payload: The inspected parameter value consists almost entirely of exploit syntax (e.g.,
UNION SELECT 1,2,3, allowing minimal wrappers like@or trailing semicolons). - Embedded Payload: The attack pattern appears inside ordinary text, user comments, articles, or descriptions.
Isolation classification scope (current):
- The isolation gadget list covers PHP/JSP live shells, Log4j JNDI lookups, and short quoted/predicate SQL (≤96 runes).
- XSS, command/RCE, SSTI, SSRF, and XXE use document shape guards, not this gadget list.
- Only hits labeled embedded skip blocking below paranoia level 5.
- Hits that stay unclassified still go through
blockableHitevidence rules; they are not auto-treated as embedded. - Technical articles and writeups are not guaranteed to always pass — isolation reduces false positives for covered gadgets, it is not a blanket content pass.
| Level | Name | Isolated Payload | Embedded Payload | Dynamic Elevation | Mechanism & Target Scenario |
|---|---|---|---|---|---|
| 0 | Record Only | Log only | Log only | No | Initial baseline profiling and traffic discovery. |
| 1 | Low Monitoring | Log only | Log only | No | Staging environments, rule dry-runs, and false-positive auditing. |
| 2 | Low-Medium | Block immediately | Pass to origin, async review | No | UGC platforms, forums, rich text editors with zero false positive tolerance. |
| 3 | Standard (Default) | Block immediately | Pass to origin, async review | No | Standard production web apps and corporate portals. |
| 4 | Medium-High | Block immediately | Pass to origin, async review | Supported (elevates to Level 5) | Critical systems under probing. Temporarily elevates to Level 5 via promote_seconds. |
| 5 | Strict Mitigation | Block immediately | Block immediately, async review | N/A (Already highest) | Financial APIs, payment backends, and active emergency mitigation. |
Notes:
- Dynamic Elevation (
promote_seconds): Under Level 4, detecting embedded attack patterns can trigger a temporary elevation to Level 5 for a specified window (e.g., 300 seconds). The elevation deadline is persisted in SQLite across service restarts.- Level 5 Constraints: Level 5 blocked samples are enqueued for audit with status
blockedand cannot be retroactively allowed, but can be converted into permanent block rules (payloads, URLs, IPs, client fingerprints).
CheeseWAF provides three independent deployment methods. Choose the one that suits your infrastructure:
Recommended for Linux physical servers and virtual machines for direct execution and low resource consumption.
Download an Alpha- pre-release from Releases, or the matching Actions artifact. The version portion is beta on master, PreTest on canary, and dev on dev; these wildcard patterns cover every channel:
| File | Platform |
|---|---|
cheesewaf-amd64-linux-*.tar.gz |
Linux x86_64 |
cheesewaf-arm64-linux-*.tar.gz |
Linux ARM64 |
cheesewaf-loong64-linux-*.tar.gz |
Linux LoongArch64 |
cheesewaf-amd64-darwin-*.tar.gz / .dmg |
macOS Intel |
cheesewaf-arm64-darwin-*.tar.gz / .dmg |
macOS Apple Silicon |
cheesewaf-amd64-windows-*.exe |
Windows x86_64 single-file CLI |
cheesewaf-arm64-windows-*.exe |
Windows ARM64 single-file CLI |
cheesewaf-amd64-windows-*.zip |
Windows x86_64 portable folder |
cheesewaf-arm64-windows-*.zip |
Windows ARM64 portable folder |
# Linux x86_64 example
tar -xzf cheesewaf-amd64-linux-*.tar.gz
cd cheesewaf-*Linux ARM64 and LoongArch64 use cheesewaf-arm64-linux-*.tar.gz or cheesewaf-loong64-linux-*.tar.gz.
# From the extracted package directory (needs cheesewaf and web/dist):
sudo ./install-linux.shOr install by hand. Copy the UI files as well as the binary, otherwise /setup returns 404:
sudo install -m 0755 cheesewaf /usr/local/bin/cheesewaf
sudo ln -sf /usr/local/bin/cheesewaf /usr/local/bin/waf-cli
sudo mkdir -p /usr/share/cheesewaf/web /etc/cheesewaf /var/lib/cheesewaf /var/log/cheesewaf
sudo cp -R web/dist/. /usr/share/cheesewaf/web/
sudo cp configs/cheesewaf.yaml /etc/cheesewaf/cheesewaf.yaml
sudo useradd --system --home /var/lib/cheesewaf --shell /usr/sbin/nologin cheesewaf
sudo chown -R cheesewaf:cheesewaf /etc/cheesewaf /var/lib/cheesewaf /var/log/cheesewafLinux archives include systemd/cheesewaf.service. Install that file. The unit grants CAP_NET_BIND_SERVICE so the non-root service can bind ports 80 and 443:
sudo cp systemd/cheesewaf.service /etc/systemd/system/cheesewaf.service# Reload systemd and enable on boot
sudo systemctl daemon-reload
sudo systemctl enable --now cheesewaf
# Check service status
sudo systemctl status cheesewafThe systemd unit keeps ProtectSystem=strict and grants the service write access only to /etc/cheesewaf, /var/lib/cheesewaf, and /var/log/cheesewaf. This lets the management API save validated configuration changes while keeping the rest of the system read-only.
The default admin listener is 127.0.0.1:9443. On the server (or over an SSH tunnel) open http://127.0.0.1:9443/setup. Loopback /setup can finish first-install without pasting a token. From another host, copy the URL from journalctl -u cheesewaf or /var/lib/cheesewaf/setup.url. Remote SERVER_IP:9443 stays closed until setup chooses a public admin strategy.
GET /api/setup returns 405; first-install status is GET /api/setup/status. Completing setup is POST /api/setup with X-CheeseWAF-Setup-Token. Login from another host still needs the console captcha; loopback API login does not.
Docker images are built from a git checkout (deploy/docker/Dockerfile). Release .tar.gz files are for systemd, not for docker compose without the repository. docker compose build produces linux/amd64 or linux/arm64 for the host CPU. The container runs as a non-root user (UID 10001) with a read-only root filesystem. The runtime image installs the distro CA bundle so outbound HTTPS to origins verifies certificates. Compose maps admin TLS to host loopback (127.0.0.1:9443); use an SSH tunnel or a separately hardened reverse proxy when remote access is required.
Save the following as docker-compose.yml:
services:
cheesewaf:
image: cheesewaf:latest
build:
context: .
dockerfile: deploy/docker/Dockerfile
user: "10001:10001"
restart: unless-stopped
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:size=32m,mode=1777,noexec,nosuid,nodev
ports:
- "8080:8080"
- "9443:9443"
volumes:
- cheesewaf-data:/var/lib/cheesewaf
- cheesewaf-logs:/var/log/cheesewaf
healthcheck:
test: ["CMD", "/usr/local/bin/cheesewaf-entrypoint", "healthcheck"]
interval: 30s
timeout: 5s
retries: 3
volumes:
cheesewaf-data:
cheesewaf-logs:# Start container in detached mode
docker compose up -d
# View logs and retrieve initial setup token
docker compose logs -f cheesewaf- Open
https://<HOST_IP>:9443/setupin your browser (admin uses HTTPS with a self-signed certificate in Docker). - Copy the temporary onboarding token from the container startup logs.
- Data and logs persist in
cheesewaf-dataandcheesewaf-logsvolumes across container restarts.
Three Windows shapes. The CLI is one cheesewaf.exe. The zip adds configs, the Web UI, and the local controller. NSIS is the graphical installer.
- Download
cheesewaf-*-windows-amd64.exeorcheesewaf-*-windows-arm64.exe. - Run it as
cheesewaf.exe:
.\cheesewaf-*-windows-amd64.exe serve --config .\configs\cheesewaf.yaml --data-dir .\data
.\cheesewaf-*-windows-amd64.exe status
.\cheesewaf-*-windows-amd64.exe stopThe data-plane binary does not need the installer. The admin UI is in the zip/DMG/tarball (web/dist next to the executable).
- Download
cheesewaf-*-windows-amd64.ziporcheesewaf-*-windows-arm64.zipand extract it (for exampleD:\CheeseWAF). - Run:
.\cheesewaf.exe serve --config .\configs\cheesewaf.yaml --data-dir .\data
.\cheesewaf.exe status
.\cheesewaf.exe stop- Run
CheeseWAF-*-windows-amd64-setup.exeorCheeseWAF-*-windows-arm64-setup.exe. - Follow the setup wizard. The installer registers Windows Service
CheeseWAF;cheesewaf.exe serveanswers Service Control Manager stop/shutdown. - Uninstall keeps
data\by default.
Windows releases bundle a lightweight local GUI controller bound strictly to loopback (127.0.0.1:17943):
- Start, stop, and restart the backend WAF process.
- Inspect process PID and operational status.
- Open the Web management console or configuration directory directly.
- Configure user-login autostart via the Windows Registry.
- Download
cheesewaf-arm64-darwin-*.dmg(Apple Silicon) orcheesewaf-amd64-darwin-*.dmg(Intel). - Open the disk image and drag CheeseWAF into Applications.
- Open CheeseWAF from Launchpad or Applications. It starts the local controller (start / stop / open the Web console).
- Signed and notarized releases should open normally. For an ad-hoc PreTest developer build only, Control-click the app in Applications, choose Open, and confirm the one-time prompt.
Runtime files go to ~/Library/Application Support/CheeseWAF. The same payload is also in cheesewaf-*-darwin-*.tar.gz if you only want the CLI.
Open the setup URL after starting the service:
http://127.0.0.1:9443/setup(https://127.0.0.1:9443/setupin Docker)- Create your administrator account and save the system key.
In the Web console, go to Sites -> Add Site:
- Domain: Enter your public domain (e.g.,
example.com). - Upstream: Enter the internal IP and port of your origin application (e.g.,
10.0.0.10:8000). - Protection Level: Select Paranoia Level 3 for standard deployments.
- Save: Configuration is applied immediately without restarting the service.
In AI Settings:
- Endpoint: Enter your LLM provider endpoint (e.g.,
https://api.openai.com/v1). - API Key & Model: Enter credentials and select the target model.
- Auto-Agree: Enable auto-commit for high-confidence threats if you want automated rule creation.
| Interface | Form Factor | Primary Usage |
|---|---|---|
| Web Console | Responsive Web application (desktop and mobile) | Site configuration, rule orchestration, threat dashboards, log analysis, AI review queue |
| Terminal CLI | Interactive TUI & command tools (waf-cli) |
Headless server management, configuration reloading, process status checks |
| RESTful API | HTTP API with Bearer Token authentication | CI/CD pipelines, automated deployments, custom integrations |
A default data/config/cheesewaf.yaml file is generated upon first startup (reference template: configs/cheesewaf.yaml):
server:
listen: "127.0.0.1:8080" # Safe local default; expose intentionally
admin_listen: "127.0.0.1:9443" # Admin plane listener
admin_public: false # Set true only with admin TLS configured
sites:
- id: "site-demo"
name: "Demo Site"
domains: ["demo.example.com"]
upstreams:
- address: "192.168.1.100:8080"
weight: 1
waf:
enabled: true
mode: "block"
paranoia_level: 3 # Paranoia Level (0–5)
semantic_policy:
auto_agree: true # Auto-commit high-confidence review verdicts
protection:
ratelimit:
enabled: true
default:
requests: 100
window: 60s
burst: 20
ip:
blacklist: []
whitelist: ["127.0.0.1", "::1"]
ai:
enabled: true
provider: "openai"
api_base: "https://api.example.com/v1"
model: "provider-default"Site custom rules live only in sites[].waf.custom_rules. The console Rules page can import YAML/JSON: it validates and dedupes first, then replaces the site set. On failure the currently working rules stay in place and the API returns an error. The CLI can import the same document:
waf-cli --config ./data/config/cheesewaf.yaml rules example --format yaml
waf-cli --config ./data/config/cheesewaf.yaml rules import --site default --file custom_rules.yaml
waf-cli --config ./data/config/cheesewaf.yaml rules export --site default --format jsonAfter you edit the config file, the process watches cheesewaf.yaml mtime, and SIGHUP reloads immediately. A load or compile failure keeps the previous rules.
| Layer | Component |
|---|---|
| Data Plane | Go 1.26, chi routing, quic-go (HTTP/3 support) |
| Detection Core | In-process AST semantic analyzer, dynamic fingerprinting, token-bucket rate limiter |
| Review Engine | Asynchronous task queues, standard Chat Completions / Messages protocol adapters |
| Storage | Embedded SQLite (modernc.org/sqlite, pure Go), optional PostgreSQL sink |
| Web Console | React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, TanStack Query |
| Terminal CLI | Cobra CLI library, Bubble Tea TUI framework |
- Go
1.26or higher - Node.js
24.xand npm
# 1. Clone repository
git clone https://github.com/LaokeQwQ/CheeseWAF.git
cd CheeseWAF
# 2. Build Web frontend static assets
cd web
npm ci
npm run build
cd ..
# 3. Build backend binary
go build -o bin/cheesewaf ./cmd/cheesewaf
# 4. Run
./bin/cheesewaf serve --config ./configs/cheesewaf.yaml# Run backend tests
go test -v ./cmd/... ./internal/...
go vet ./cmd/... ./internal/...
# Frontend type checking and tests
cd web && npm run typecheck && npm test && cd ..
# Generate and replay the governed security corpus
make security-corpusGovernance runs are read-only and recursively enumerate every .jsonl or .jsonl.gz file below internal/engine/semantic/testdata/ at runtime. The pipeline is ordered as: global deduplication → structural/semantic triage → selection and cleaning → second review. It writes formal.jsonl, quarantine.jsonl, and an auditable manifest.json to a temporary directory. Git-ignored large corpora are represented as optional inputs in the manifest when absent; nested and compressed copies are not silently omitted.
make corpus-governance audits all available corpora while keeping their rows in a quarantine snapshot. make security-corpus separately builds a hash-bound formal snapshot from repository-curated sources, pins the input hashes, exact source/label/category coverage, governance policy and formal artifact hash, and requires zero hard rejects, then feeds only that snapshot to both analyzer replay and semantic evaluation. The malformed pat-sqli-00119 record remains preserved in an explicitly pinned quarantine-only file; it is not silently replaced or removed from the audit denominator. CI also requires at least 250 benign and 10,000 attack rows before applying FPR below 0.8% and TPR of at least 99% to this governed regression snapshot. This does not claim that an independent blind set or every quarantined research corpus already meets the same target.
make corpus-governance
make security-corpus- ACME Certificate Reload Profiles
- Semantic Evaluation Platform
- Semantic Corpus Governance
- Release, Upgrade and Rollback
- Protection Policy & Roadmap
- Paranoia Level Code Mapping
- Performance Optimization Notes
- Windows Packaging Guide
This project is licensed under the Apache License 2.0.
