apPosture WAAP Documentation
The complete reference for every module, function, setting and API endpoint — from the OWASP-CRS data plane to the real-time AI detection engine, API security, deployment, licensing and operations.
Overview & positioning
apPosture is a self-hosted WAAP — Web Application & API Protection platform. It combines, in one on-prem deployment, an OWASP-CRS web application firewall, deep API security (discovery, OWASP API Top 10, posture), bot & DoS defense, and a real-time AI/ML detection engine — all controlled from a single console and licensed by the number of protected domains.
What sets it apart from a commodity WAF: every request flows through a layered pipeline (signatures → anomaly baselines → API-abuse heuristics → bot fingerprinting) whose scores are fused into a single explainable 0–100 risk verdict, and the platform continuously discovers and classifies your APIs rather than only matching attack signatures.
Architecture
Two planes, clean separation:
- Data plane — apPosture WAF engine — OWASP CRS v4 + rate limiting, JWT validation, distributed state, response rewriting;
response-rewrite). Terminates traffic on
:8080, inspects every request, enforces verdicts, hot-reloads config from the control plane over the data-plane admin API (:2019, internal only). - Control plane — the control-plane service backend (
:8090internal) + the dashboard dashboard (:3010). The browser talks only to the dashboard origin;/api/*is proxied server-side to the backend (no CORS). A background worker loop runs the auto-ban, adaptive-attack, API-block, AI engine, alerting and feed-sync evaluators every ~15s. - Data stores — PostgreSQL (API inventory, request log, audit, AI verdict history) and Redis (distributed rate-limit state for multi-node).
/api/* is proxied server-side.Internet ─▶ (edge/CDN scrubbing — optional, for volumetric DDoS)
─▶ apPosture WAF engine (OWASP CRS) :8080 ── protected app/API traffic
│ hot-reload ▲ admin :2019
─▶ Dashboard :3010 ──▶ Control-plane API :8090
└── Postgres · Redis
| Port | Service | Exposure |
|---|---|---|
8080 | WAF data plane (protected traffic) | Public — send app traffic here |
8443 | JA3/JA4 TLS-fingerprint proxy | Public (optional HTTPS entry) |
3010 | Dashboard (management UI) | Host-only by default (ADMIN_BIND) |
8095 | Control-plane API | Host-only by default |
2019 | the data plane admin (hot-reload) | Internal network only |
Installation
One file to edit per deployment: .env (copied from .env.example). The one-command
installer generates secrets, builds/loads images, starts the stack and prints the URL + credentials.
--offline installs from a prebuilt bundle.Single VM / on-prem
sudo ./install.sh # online: build from source, localhost-bound
sudo ./install.sh --bind 0.0.0.0 -y # reachable on the LAN, non-interactive
sudo ./install.sh --domain waap.example.com -y # automatic HTTPS (Let's Encrypt, no certbot)
The installer runs preflight (Docker present, ports free), auto-generates AUTH_SESSION_SECRET,
admin password and DB password, waits for health, and prints the dashboard URL, login, and WAF entry point.
Re-running ./install.sh performs an in-place upgrade (keeps .env + data). Stop with
./uninstall.sh (add --purge to also delete data volumes).
Air-gapped / no internet
# on an internet-connected machine:
./scripts/build-offline-bundle.sh # → dist/apposture-offline-*.tar.gz (images + installer)
# on the customer host (offline):
tar xzf apposture-offline-*.tar.gz && cd apposture-offline-* && sudo ./install.sh --offline
Kubernetes
helm install apposture deploy/helm/apposture \
--namespace apposture --create-namespace \
--set image.registry=ghcr.io/your-org --set image.tag=1.0.0 \
--set auth.adminInitialPassword='ChangeMe!' \
--set auth.sessionSecret="$(openssl rand -base64 36)"
A Terraform module (deploy/terraform) wraps the Helm release. See Scaling & HA.
Automatic HTTPS
install.sh --domain <fqdn> enables a bundled the data plane edge (compose profile tls) that
auto-provisions and renews a Let's Encrypt certificate for the dashboard domain — no certbot, no manual nginx.
Requires the domain's DNS A/AAAA record to point at the host and ports 80/443 reachable. ACME account/certs
persist in the edge-data volume across restarts. Email is taken from ACME_EMAIL (defaults to the
admin email).
Configuration reference (.env)
Every environment-specific value is read by docker-compose.yml via ${VAR:-default}.
| Variable | Default | Purpose |
|---|---|---|
ADMIN_EMAIL | — | Seed admin login email |
ADMIN_INITIAL_PASSWORD | (generated) | First-login password (rotate after) |
AUTH_SESSION_SECRET | (generated) | HMAC key signing session tokens — keep stable |
ADMIN_BIND | 127.0.0.1 | Host bind for dashboard/API (use 0.0.0.0 for LAN) |
WAF_PORT / UI_PORT / API_PORT / JA3_PORT | 8080/3010/8095/8443 | Host port mappings |
POSTGRES_USER/PASSWORD/DB | apposture | Database credentials |
UPSTREAM_CUSTOMER / UPSTREAM_PAYMENT | mock-*:8000 | Default protected upstreams |
APP_BRAND / APP_BRAND_SUB / APP_TAGLINE | apPosture / WAAP | Build-time white-label branding |
DASHBOARD_DOMAIN / ACME_EMAIL | — | TLS edge domain + ACME email |
.env and rebuild the frontend image.Licensing
apPosture is licensed by number of protected domains, verified offline (no phone-home). The vendor signs a license with an RSA private key; the product embeds only the public key and verifies the signature locally (pure-stdlib RSA + PKCS#1 v1.5/SHA-256). Customers cannot forge a license or raise their own limit.
License payload (signed)
{ "customer": "Acme Bank", "max_domains": 5, "issued": …, "expires": …|null, "edition": "enterprise" }
Vendor: issue a license
python3 scripts/license_tool.py keygen # one-time: private key + public key to embed
python3 scripts/license_tool.py issue --customer "Acme Bank" --domains 5 --days 365
Customer: activate
Paste the key into Settings → License (or POST /api/license). Status, used/allowed domains,
edition and expiry are shown on the License page.
| State | Behaviour |
|---|---|
| Valid | Up to max_domains protected sites may be configured |
| Trial (no key) | 1 domain allowed |
| Expired | Drops to the trial add-limit, but existing protection keeps running |
| Forged / tampered | Rejected (signature fails) → trial limit |
403. A security product is never bricked by a lapsed license — it just won't add new domains.How a request is processed
Every request flows through an ordered inspection pipeline at the data-plane edge. Cheap, decisive checks run first (IP reputation, bans) so malicious traffic is dropped before expensive inspection; the AI engine fuses the upstream signals into the final verdict. A request reaches your application only if it survives every stage.
WAF — OWASP CRS v4
apPosture's data-plane WAF is a high-performance embedded inspection engine running the full OWASP Core Rule Set v4. Every request is inspected across multiple rule phases and accumulates a weighted anomaly score; the request is blocked when the score crosses the inbound/outbound threshold — so a single weak signal won't false-positive, while a real attack trips several rules at once.
Core settings
| Setting | Values | Meaning |
|---|---|---|
mode | On | DetectionOnly | On blocks; DetectionOnly logs without blocking (tuning) |
paranoia_level | 1–4 | Higher = stricter rules, more potential false positives |
inbound_threshold | int (default 5) | Anomaly score at which an inbound request is blocked |
outbound_threshold | int (default 4) | Outbound (response) block threshold |
Rule Builder & CRS categories
The Rules page exposes the 13 OWASP CRS protection categories — each can be toggled on/off and
edited with per-category path exclusions (keep the protection global but skip it on specific
endpoints that legitimately trip it). Exclusions render as the WAF engine ctl:ruleRemoveByTag rules
(ids 1009000+).
| Category key | Protects against (CRS group) |
|---|---|
sqli | SQL injection (942) |
xss | Cross-site scripting (941) |
rce | Remote code execution / web shells (932) |
php / java / generic | PHP / Java / generic command & SSTI injection (933/944/934) |
lfi / rfi | Local / remote file inclusion & SSRF (930/931) |
protocol / method | Protocol enforcement, request smuggling, method enforcement (920/921/911) |
scanner / fixation / dataleak | Scanner detection (913), session fixation (943), outbound data-leakage (950s) |
Custom rules — a Visual builder (variable · operator · value · action · phase) and a raw seclang
(Advanced) editor. Rules can be enabled/disabled/edited individually; disabled rules are kept but not loaded
into the engine. Custom-rule ids start at 1000000+.
Rate limiting
Centralized rate limiting via the data-plane rate limiter, optionally Redis-backed for global limits across multiple nodes.
| Setting | Meaning |
|---|---|
rl_enabled | Master switch |
rl_events / rl_window | Default zone: allowed requests per window (e.g. 100 / 1m) |
rl_distributed | Redis-backed shared counters (required for multi-replica) |
rl_zones | Per-path/method zones: {name, match_path, key, events, window} |
rl_trust_proxy / rl_trusted_proxies | Resolve the real client IP from X-Forwarded-For behind an edge/CDN |
endpoint_limits | Tight per-IP caps on expensive endpoints: {path, method, events, window} |
ip (per client — XFF-aware when trust-proxy is on), global (one shared bucket),
or header:Name (e.g. per API key).Flood & DoS protection
Layer-7 flood defense, all default-off so they're opt-in:
| Feature | Settings | What it does |
|---|---|---|
| Global flood limit | flood_global_enabled/events/window | Aggregate cap across all clients (distributed flood) |
| Per-IP burst cap | flood_burst_enabled/events/window | Short-window per-IP burst limit |
| Slowloris timeouts | flood_timeouts_enabled, flood_read_header/body, flood_write, flood_idle | Server read/write/idle timeouts vs slow-request attacks |
| Auto-ban | flood_autoban_enabled/threshold/window_sec/duration_sec | Temp-ban IPs that repeatedly hit 429 (with escalation on repeat offense) |
| Adaptive under-attack mode | attack_mode (off/auto/on), attack_spike_factor, attack_min_rpm, attack_burst_* | Auto-tightens per-IP limits when current RPM spikes over the learned baseline |
| JS challenge | challenge_enabled, challenge_paths | JS-cookie interstitial gating selected paths (blocks non-JS bots/scrapers) |
Auto-banned IPs are enforced at the data-plane edge via a phase-1 client_ip deny (trusted-proxy-aware,
so the real client is banned) and recorded in the threat-intel list.
DDoS — L3/L4 hardening & the honest limit
scripts/ddos-l34.sh applies host-level nftables connection-rate limits + SYN-cookie/sysctl
hardening. Honest scope: L7 flood + abusive-client defense is in-product; true volumetric DDoS
(tens-to-hundreds of Gbps) saturates the NIC before the data plane sees it and requires upstream edge scrubbing
(Cloudflare Magic Transit, AWS Shield, Akamai). apPosture is the L7 layer behind that edge. See
Scaling & HA for measured throughput (~80k req/s/node).
Bot defense
A CRS-style composite scoring engine in the WAF engine: multiple weighted signals accumulate into
tx.apb_score; the request is blocked when apb_score ≥ bot_score_threshold (default 5) unless it
is a verified good bot.
| Signal | Weight |
|---|---|
| Scanner / offensive tool (sqlmap, nuclei…) | +6 |
| Automation / HTTP library (curl, python, go-http…) · empty UA | +5 |
| Headless browser (HeadlessChrome, Selenium…) | +4 |
| Generic crawler / spider | +3 |
| Missing Accept / Accept-Language / Accept-Encoding | +2 / +2 / +1 |
Good-bot verification (anti-spoofing)
A User-Agent claiming to be Googlebot is trivially forged. With bot_verify_rdns enabled,
each claimed crawler is checked by forward-confirmed reverse DNS (FCrDNS): reverse-DNS the IP → confirm
the hostname is on the crawler's official domain → forward-DNS it back to the same IP. A claim that fails is an
impostor. POST /api/bots/verify does an on-demand check; the engine auto-blocks impostors when
bot_action=block.
| Setting | Meaning |
|---|---|
bot_action | monitor (log) | block (deny ≥ threshold) |
bot_score_threshold | Composite block threshold (default 5) |
bot_allow_verified | Exempt verified good bots (Googlebot/Bingbot…) |
bot_verify_rdns | FCrDNS verification (catch spoofed crawlers) |
bot_check_headers / bot_block_automation | Header heuristics / score HTTP libraries |
bot_ja3_blocklist | Manual hard-block by JA3 fingerprint hash |
The JA3/JA4 TLS-fingerprint proxy (:8443) captures fingerprints so a bot can be blocked even behind a
spoofed User-Agent.
Real-time AI detection engine
The engine (app/aiengine.py) scores the live request stream server-side and fuses four detection
layers into a single explainable verdict. It maintains online EWMA population baselines (mean+variance
per feature, snapshotted to /data/ai_baselines.json so they survive restarts and adapt to drift) and
scores each client by z-score against the live population.
Detection layers
| Layer | What it scores |
|---|---|
| signature | Requests already blocked by OWASP-CRS (deterministic ground truth) |
| anomaly | z-score of request-rate, payload entropy, parameter cardinality, error rate, 404 scanning |
| api_abuse | BOLA (object-ID enumeration), BFLA (admin w/o auth), credential stuffing |
| bot | Automation/scanner UA, empty UA, User-Agent rotation |
Fusion → verdict ladder
Risk = weighted sum of the four layers (weights normalized) → 0–100, with a confidence value and a list of contributing signals (layer, name, points, evidence) so every score is explainable. The verdict maps to a graduated, enforced response:
| Verdict | Threshold | Enforcement (when ai_action=block) |
|---|---|---|
| BLOCK | ≥ ai_risk_threshold (default 80) | a data-plane client_ip deny (auto-ban) |
| CHALLENGE | ≥ threshold−20 | JS interstitial for the IP on all paths (real browsers pass, bots stall) |
| RATE_LIMIT | ≥ threshold−35 | Tight per-IP throttle zone (15 req / 10s) |
| ALLOW | below | Pass |
| Setting | Meaning |
|---|---|
ai_enabled | Master switch (scores in monitor mode too) |
ai_action | monitor (score/log) | block (enforce the ladder) |
ai_risk_threshold | BLOCK cutoff 0–100; challenge/rate-limit derive from it |
ai_window_sec | Live scoring window (default 300s) |
ai_w_signature/anomaly/api_abuse/bot | Fusion weights (tunable via sliders; normalized live) |
ai_block_seconds | Enforcement duration per offender |
SOC console & attack simulator
The /soc page is a live SOC command-center: RPS / clients / high-risk KPIs, a verdict-distribution donut, attack-type (dominant layer) bars, the live client risk stream (click any row for the full explainability drawer with per-layer scores, signals and OWASP-API/MITRE ATT&CK mapping), an adaptive policy panel (engine on/off, action, risk threshold, layer-weight sliders) and a persisted detection history timeline.
The attack simulator injects real malicious request waves through the WAF (POST /api/ai/simulate
— sqli, xss, cred_stuffing, bola, l7_flood, anomaly) so the engine + the WAF engine visibly react; verdicts are
recorded in the history (deduped per IP ~5 min, pruned by the retention policy).
A public, no-auth marketing demo of the engine (in-browser simulation) runs at /demo.
API discovery & inventory
Endpoints are discovered automatically from WAF traffic (and from gateway connectors /
agentless ingestion). Each endpoint is templatized (/orders/42 → /orders/{id}) and assigned a
risk score (0–5) + band from signals: reachable-without-auth, data sensitivity, state-changing method,
sensitive path keyword, traffic volume. The Inventory page shows access type, auth type, hits, first/last seen,
shadow flag and data classification, with CSV export. GET /api/inventory · GET /api/inventory/stats.
Per-endpoint data classification
Each endpoint is classified by the sensitivity of data it handles, derived from PII detection:
| Level | Data categories | Regulations |
|---|---|---|
| Restricted | Payment card (PAN), National ID/SSN, auth token/secret | PCI-DSS, Secret |
| Confidential | Email, phone, IBAN | GDPR, PII, PCI-DSS |
| Internal | No PII but a sensitive path keyword (admin/auth/account) | — |
| Public | None detected | — |
Classification feeds the risk score (restricted data weights highest) and the Inventory "unprotected sensitive" KPI (sensitive endpoint reachable without auth).
Shadow / zombie & spec posture-gap
Upload an OpenAPI spec (Inventory page or POST /api/spec) to enable spec posture analysis
(GET /api/posture-gaps):
- Shadow — endpoints seen in live traffic but absent from the spec (undocumented attack surface).
- Zombie — operations documented in the spec but never observed in traffic (stale/forgotten).
- Coverage % — observed ÷ documented operations.
- Per-operation gaps — documented + observed operations with a posture problem: reachable without auth,
spec declares no
security, or sensitive data exposed without auth (severity high/medium).
OWASP API Top 10 — real-time BOLA/BFLA
The API-threats detector finds and (optionally) blocks business-logic abuse in real time:
- API1 BOLA / IDOR — one client enumerating many distinct object IDs on a templated route.
- API5 BFLA — low-privilege client hitting admin/management paths without auth.
- API2 Broken auth — credential stuffing (login + high failure rate + IP/UA spread).
| Setting | Meaning |
|---|---|
api_protect_mode | monitor | block |
api_bola_threshold / api_bola_window_sec | Distinct objects / admin hits within the window to trigger |
api_block_seconds | How long to block an offender |
In block mode the offender's real client IP is auto-blocked via the data-plane client_ip deny used by
flood auto-ban. Findings surface on the API Threats page and via GET /api/api-threats.
Data-flow mapping & east-west
The Data Flow page (GET /api/data-flow) maps which sensitive data categories flow through which
endpoints and protected sites, and flags unprotected flows (sensitive endpoint reachable without auth).
The East-West page (GET /api/east-west, POST /api/ingest/mesh) ingests service-to-service
(internal) traffic from a sidecar / service mesh, builds a caller→callee map, and flags
unauthenticated internal calls (a zero-trust gap) — internal endpoints also flow into the inventory.
Auth enforcement (JWT & per-endpoint)
Enforces authentication on protected paths at the WAF edge:
- Per-endpoint presence — a request to any prefix in
auth_protected_pathswith noAuthorization/X-API-Keycredential →401(the WAF engine phase-1 chained rule, ids1010000+). Works for arbitrary sub-paths, not just whole sites. - Full JWT validation — on protected sites with a signing key (
auth_secret) orauth_jwks_urlset, the token signature is validated (the data-plane JWT validator). If no key is set, the JWT validation block is safely skipped (presence enforcement still applies).
| Setting | Meaning |
|---|---|
auth_enabled | Master switch |
auth_protected_paths | Path prefixes requiring a credential |
auth_alg / auth_secret / auth_jwks_url | JWT algorithm, HS256 key, or JWKS endpoint |
Shift-left API testing (CI/CD)
Run an API security gate before deploy. POST /api/ci-scan statically scans an OpenAPI spec
(no live traffic) and returns a pass/fail verdict against gates (max_high / max_medium) plus a
posture score and per-finding rules: sensitive-no-auth, unprotected-write, bola-risk,
missing-auth, bola-review.
# pipeline gate — exit 1 on breach:
APPOSTURE_URL=https://waap.example.com APPOSTURE_TOKEN=<token> \
./scripts/apposture-scan.sh openapi.json 0 5 # max_high=0, max_medium=5
A ready-to-use GitHub Actions step ships in scripts/apposture-scan.github-actions.yml (needs only
curl + python3).
Gateway connectors & ingestion
Pull traffic into discovery/detection without inline proxying. POST /api/gateway/{type} normalizes
each gateway's access-log schema into the engine:
| Type | Source |
|---|---|
kong | Kong HTTP Log plugin |
aws | AWS API Gateway access log |
nginx | nginx JSON access log |
apigee | Apigee analytics record |
generic | Generic {method,uri,status,ip,user_agent} |
Generic agentless ingestion: POST /api/ingest accepts an events array or a HAR archive.
Schema enforcement & sensitive data
Schema enforcement (schema_action: ignore/alert/block) — positive security: a request whose
method+path is not in the uploaded OpenAPI spec can be alerted or blocked. Sensitive data —
pii_detect flags PII (card/email/token/IBAN/SSN/phone) in responses; pii_mask masks card numbers
in responses (the response-rewrite filter); privacy_mode masks PII in stored data (metadata-only).
GraphQL — graphql_protect blocks introspection (__schema/__type).
Threat intelligence feed
Auto-pull IP reputation and block at the WAF edge. Built-in TOR exit-node blocking
(ti_tor_enabled) plus an optional custom bad-IP feed URL (ti_feed_url, newline or JSON),
refreshed on ti_feed_interval_hours. Synced IPs render as a phase-1 deny (rule 1006000).
Manual import + one-click block of live-traffic matches is on the Threat Intel page
(GET/POST /api/threat-intel).
Credential abuse / ATO
The Credentials page scores account-takeover risk per source: login attempts, failure rate, IP/UA spread,
distinct accounts targeted. Password policy integrates HIBP (policy_block_pwned) via k-anonymity
to reject known-breached passwords at user create/update.
Virtual patching & managed feed
Virtual patching — a CVE catalog (rule ids 1007xxx) lets you apply a virtual patch (block a
known exploit pattern) without touching the app; GET /api/vpatch/catalog, POST /api/vpatch.
Managed rule/threat feed (MRF) — scheduled puller for a curated rule + IP-reputation feed
(mrf_enabled, mrf_url, mrf_interval_hours); empty URL uses the bundled apPosture baseline.
Protected Sites
Path-prefix → upstream routing. sites = [{name, prefix, upstream, protected}]; empty falls
back to the bundled customer/payment demo upstreams. The number of configured sites is the licensed
"domain" count — see Licensing. Subset-editing pages preserve the full settings
object (spread ...loaded before overriding) so unrelated fields aren't wiped on save.
Integrations — SIEM, SSO, MRF
SIEM connectors (siem_connectors) — multi-target export: Splunk HEC, Elasticsearch, Microsoft
Sentinel, syslog (RFC5424), CEF, generic webhook. Security events (auto-bans, AI blocks, API blocks) emit
asynchronously. SSO / OIDC (sso_*) — authorization-code login ("Sign in with SSO"): issuer
discovery, client id/secret, redirect URI, default role, allowed email domain. Notifications — legacy
single webhook (siem_webhook_url) kept for compatibility.
Alerting
Threshold rules over live traffic → multi-channel notifications. Each rule:
{metric, threshold, window_min, type, target, cooldown_min}. Metrics: blocked, requests, errors,
block-rate %. Channels: Slack, generic webhook, PagerDuty Events v2. Evaluated continuously by the worker loop
with per-rule cooldown. POST /api/alerts/test fires a test.
Compliance reporting
The Compliance page reports live posture against PCI-DSS, GDPR, SOC 2 and OWASP frameworks — each
control's status is derived from real config signals (WAF on, TLS, auth enforcement, retention, audit, PII
handling, etc.) so the report reflects the actual running configuration. GET /api/compliance.
Governance — audit, config versioning, policy, tuning
- Audit log — every admin/governance action (settings diff, config apply, IP/threat block, user
CRUD, license activation, rollback) recorded with actor + role + source IP + timestamp + human-readable
summary.
GET /api/audit; CSV export + filters on the Audit page.audit.record()never raises. - Config versioning & rollback — every saved configuration is snapshotted (cap 50). The Config
History page lists versions (id, when, author, change summary) and rolls back to any version in one click —
the restored config is pushed live and the rollback itself is audited.
GET /api/config/versions,POST /api/config/rollback. - Policy & retention — log retention windows (
retention_requests_days,retention_audit_days; AI verdict history follows the request window), password policy, session TTL, lockout threshold, 2FA-required-for-admin. Pruning runs hourly.GET /api/policy/stats. - False-positive tuning — learning mode: the most-triggered CRS rules with their top paths; a rule
firing heavily on a narrow path set is a likely false positive → suggested exclusion.
GET /api/fp-suggestions.
Users & RBAC
Real login: stdlib-only PBKDF2-HMAC-SHA256 passwords + HMAC-SHA256 signed session tokens; TOTP 2FA
(RFC 6238). Roles: admin (full — settings, IAM, governance), operator (tune WAF/flood/rules; no
governance/IAM), viewer (read-only). The role comes from the signed token, never a header.
Mutating endpoints enforce role via _require(request, *roles); governance fields (IAM, integrations,
license…) are admin-only. Users page: provisioning, inline role change, suspend/activate, per-user activity,
roles & permissions matrix, password reset, 2FA enrollment.
Analytics & traffic
Dashboard, Analytics and Traffic pages provide Cloudflare/Swetrix-style telemetry: requests-over-time (1h/6h/24h/7d), block rate, top attacked endpoints, top attacker sources, attack-type distribution, live request stream with cursor pagination. All absolute times display in Baku time (GMT+4); storage stays UTC.
API reference (selected)
| Method · Path | Purpose |
|---|---|
POST/api/login | Authenticate → session token (OTP step if 2FA) |
GET/api/settings · PUT | Read / update configuration (role-gated, license-enforced) |
POST/api/apply | Render & push config to the data plane (hot-reload) |
GET/api/ai/soc · /api/ai/history | Live AI scoring + persisted verdict timeline |
POST/api/ai/simulate | Inject an attack wave through the WAF |
GET/api/inventory · /api/posture-gaps · /api/data-flow · /api/east-west | API security views |
POST/api/ci-scan | Shift-left OpenAPI security scan (pass/fail) |
POST/api/gateway/{type} · /api/ingest · /api/ingest/mesh | Connector / agentless / east-west ingestion |
GET/api/license · POST | License status / activation (admin) |
GET/api/audit · /api/compliance · /api/config/versions | Governance & compliance |
Scaling & HA
Measured single-node throughput (16 vCPU, the full WAF inspection path): ~80,000 req/s, ~1.1 ms p50 /
~6 ms p99 — and a WAF block costs the same as a pass (the limit is CPU, not rule evaluation). Scale L7
capacity horizontally: the stateless data plane runs N replicas behind the LoadBalancer for ~80k × N
req/s, with Redis-distributed rate limiting (rl_distributed) for global limits and a single
control plane (the evaluator loops are single-writer). Volumetric (Gbps) DDoS needs upstream edge scrubbing.
Full detail in deploy/SCALING.md.
Backup & migration
Full-state migration carries DB + config volume + .env: scripts/backup.ps1 (Windows) →
apposture-backup/ (db.sql via pg_dump --clean --if-exists, control-data.tgz,
env.bak); scripts/restore.sh (on the VM) builds, starts and restores it in one command. DB
restore is idempotent. Runbook: MIGRATION.md.
Threat coverage matrix
Which module catches which threat, and the default response. Most attacks are caught by several layers — the AI engine fuses them so a multi-signal attacker scores higher than any single check would show.
| Threat | Primary module(s) | Default action | OWASP |
|---|---|---|---|
| SQL injection | WAF (CRS 942) · AI signature layer | Block (anomaly ≥ threshold) | A03 |
| XSS | WAF (CRS 941) | Block | A03 |
| RCE / command injection / web shells | WAF (CRS 932/934) | Block | A03 |
| Path traversal / LFI / RFI / SSRF | WAF (CRS 930/931) | Block | A01/A10 |
| BOLA / IDOR (object enumeration) | API-abuse detector · AI api_abuse layer | Monitor → auto-block offender | API1 |
| BFLA (admin without auth) | API-abuse detector · auth gate | Monitor → block · 401 | API5 |
| Broken auth / unauthenticated sensitive endpoint | Per-endpoint auth · posture-gap | 401 · flagged | API2/API3 |
| Credential stuffing / ATO | Credential-abuse · AI api_abuse · HIBP | Score → block · reject pwned | API2 |
| Scrapers / automation / scanners | Bot scoring · JA3/JA4 | Block ≥ threshold | API6 |
| Spoofed good bot (fake Googlebot) | FCrDNS verification | Block impostor | — |
| L7 flood / slow-loris | Flood limits · timeouts · auto-ban · attack mode | 429 → temp-ban | — |
| Volumetric DDoS (Gbps) | Edge/CDN scrubbing (upstream) | Out of scope for the node | — |
| Shadow / undocumented API | Discovery vs OpenAPI spec | Flagged (shadow) | API9 |
| Sensitive-data exposure | PII detection · data classification · masking | Detect · mask · flag | API3 |
| Zero-day / novel anomaly | AI anomaly layer (EWMA z-score) | Risk verdict → challenge/block | — |
| Known CVE exploit pattern | Virtual patching · managed feed | Block (virtual patch) | — |
Glossary
| Term | Meaning |
|---|---|
| WAAP | Web Application & API Protection — the category combining WAF, API security, bot & DDoS defense in one platform. |
| Data plane | The inline component that terminates and inspects traffic and enforces verdicts. |
| Control plane | The management component (dashboard + API + evaluator loop) that configures the data plane. |
| OWASP CRS | OWASP Core Rule Set — the industry-standard signature rule set for web attacks. |
| Paranoia level | CRS strictness 1–4; higher catches more but may raise false positives. |
| Anomaly score | Weighted sum of matched rules; a request blocks when it crosses the threshold (no single weak signal trips it). |
| BOLA / IDOR | Broken Object Level Authorization — a client accessing objects it shouldn't, e.g. enumerating IDs (API1). |
| BFLA | Broken Function Level Authorization — reaching privileged/admin functions without authorization (API5). |
| EWMA | Exponentially-Weighted Moving Average — how the AI engine keeps adaptive, drift-aware behavioural baselines. |
| z-score | How many standard deviations a client's behaviour is from the live population baseline. |
| FCrDNS | Forward-Confirmed reverse DNS — verifies a crawler is genuine (rDNS → domain → forward-DNS back to the IP). |
| JA3 / JA4 | TLS-handshake fingerprints that identify a client even behind a spoofed User-Agent. |
| Shadow / Zombie API | Shadow = live but undocumented; Zombie = documented but never seen in traffic. |
| Virtual patch | A WAF rule that blocks a known exploit pattern without changing the application. |
| Verdict ladder | The graduated AI response: ALLOW → RATE_LIMIT → CHALLENGE → BLOCK by risk. |
| East-west traffic | Internal service-to-service API calls (vs north-south = external edge traffic). |
This documentation reflects the running platform — a self-hosted WAAP built on the OWASP Core Rule Set v4, with PostgreSQL + Redis.