How AIWAF Works
AIWAF sits inside the application request lifecycle. Framework adapters turn live HTTP requests into policy inputs, deterministic controls make immediate decisions, and optional anomaly models add evidence from recent behavior.
Source and package versions
One AIWAF repository.
Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/.
Source and canonical README.
Versions shown describe the source checkout; package releases are independent.
Current Python/Node source targets are aiwaf 1.1.8 (Python) and
aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and
WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.
Two connected execution paths
The system has a request path for enforcing the current policy and a learning path for improving future decisions. Configuration, route metadata, runtime stores, and model artifacts connect them.
- Framework adapterExtract method, path, headers, client address, and available handler metadata.
- Policy and checksSelect applicable protections, read state, and return an early denial when a check fails.
- Application handlerAllowed requests reach the normal application code.
- Response observationsRecord status, duration, and behavior; response-aware adapters may make another decision.
This is a conceptual flow, not a universal middleware ordering. Python wrappers, Node middleware, and Java filters attach to different framework hooks. The runtime-specific pages below explain the actual execution boundaries.
Responsibilities of each layer
| Layer | Responsibility | Example |
|---|---|---|
| Adapter | Read framework request/response data and intercept execution. | Django middleware, Express middleware, Spring filter. |
| Policy planner | Combine enabled middleware with route metadata and path rules. | A webhook may run header checks without form timing. |
| Deterministic checks | Enforce concrete limits and matching rules. | A rate window over its configured maximum returns a denial. |
| Behavior model | Score a feature vector using a trained forest. | Repeated unknown-route probes can add anomaly evidence. |
| Runtime state | Remember recent activity, exemptions, blocks, and learned keywords. | A later request observes an active IP block. |
| Learning pipeline | Build future models and keyword state from recorded traffic. | A scheduled job trains from access logs. |
How route policies become decisions
A manifest records discovered routes, methods, and inferred handler intent. Source analysis can supply signals such as JSON responses, form handling, or authentication calls when framework metadata is incomplete. The manifest compiler translates those signals into middleware disablement and rate-limit overrides.
The runtime combines those generated rules with explicitly configured path policies and decorator or annotation metadata. A protection runs only when it is enabled and applicable under that runtime's policy rules. An auto selection starts from the canonical set and omits checks unsupported by detected application signals; it is not itself an anomaly detector.
For example, an API endpoint may omit HTML form timing while keeping headers and rate limits. A login form needs different checks. Keep inferred policies reviewable: a route name or return type is evidence about intent, not proof of authorization.
A block is a decision; a blocklist is state
A failing header, method, or rate check can reject the current request. Some checks also record an offense or create a temporary IP block. Those are separate effects: returning a denial does not imply that every later request is permanently blocked.
Reputation handling records weighted offenses and can escalate temporary block durations. Later requests consult block expiry and exemption rules. Which checks mutate reputation and which response statuses they return are runtime-specific.
State ownership explains multi-worker behavior
| State category | Typical contents | Architectural consequence |
|---|---|---|
| Recent enforcement state | Rate buckets, form timestamps, UUID scores, recent request history. | Independent worker memory creates independent windows and counts. |
| Operational stores | Blocklists, exemptions, geo policy, learned keywords. | Persistence across restarts is different from consistent access across processes. |
| Model artifacts | Forest state, feature schema, training metadata. | Loading the same artifact does not share rate-limit or blocklist state. |
A local file can persist data while leaving other request counters process-local. Choose sharing separately for every state category. Java's Redis backend shares enforcement state atomically; Node rate limiting accepts a shared cache; Python sharing depends on the adapter and its configured stores.
How anomaly detection contributes
An Isolation Forest repeatedly partitions feature samples using random feature choices and split points. Samples isolated in fewer splits tend to receive more anomalous scores. The forest learns a distribution of request behavior; it does not identify a vulnerability or understand the application's authorization rules.
The host runtime decides whether a score is enough to block. Model availability, training volume, thresholds, route eligibility, and recent-behavior confirmation can all affect that decision. For example, Node's unknown-route path requires both a sufficiently trained model and scanning-related behavior before issuing an anomaly block.
| Feature | What it describes | Why it helps |
|---|---|---|
path_len | Length of the request path. | Unusually long probing paths. |
kw_hits | Matches against malicious keywords. | Known probing patterns within a path. |
resp_time | Response duration in seconds. | Behavior that differs from the normal timing distribution. |
status_idx | An encoded response-status category. | Response outcomes without treating status codes as continuous measurements. |
burst_count | Requests associated with the client in the burst window. | Rapid repeated activity. |
total_404 | Not-found responses in the relevant per-client history. | Repeated discovery of nonexistent routes. |
The feature order is part of the model contract. A trainer and scorer must agree on the order, status mapping, time units, and window semantics. Summary fields ending in _ms use milliseconds; the feature vector uses seconds. Sharing feature names alone does not make every model artifact interchangeable.
The learning loop
- Request logsCompleted responses supply paths, client identity, status, and timing.
- Feature extractionRecords are normalized and combined with per-client activity windows.
- Train and reviewVolume thresholds gate model training; route exemptions filter learned keywords.
- Publish artifactsThe runtime loads persisted model state and updated learned keywords.
The training job is separate from ordinary application request handling. Reading logs and rebuilding a forest does not need to happen for every request. Runtime keyword learning, where enabled, is a separate mechanism that can use completed-response signals.
Current Python model persistence uses JSON rather than executable Python-object serialization. Java can exchange the Python Rust-model forest state for the supported schema. JavaScript-native artifacts and legacy formats require their own compatibility checks.
What happens after the handler
Response observations make real status and duration available. This matters for distinguishing a normal request from repeated 404 probing. A response-aware integration may evaluate behavior after the handler returns, but a response already committed or streamed to the client cannot be replaced.
Java's Spring filter explicitly distinguishes an uncommitted synchronous response from committed or asynchronous output. Other adapters use their framework's hooks for logging and learning. Avoid assuming that post-response scoring can prevent every byte from leaving the application.
Read the runtime internals
Python native request engine
Release candidate: this page documents Python 1.1.8 and Rust/Python 0.2.7 in the current source checkout. Source versions do not establish registry availability. Python 1.1.8 requires aiwaf-rust>=0.2.7; framework dependencies remain extras.
Rust owns the native CSV pipeline configuration, enforcement order, SQL and keyword inspection, geo/blocklist decisions, rate buckets, form timing, UUID scores, anomaly history/inference, keyword learning, and CSV logging. Python supplies framework routes, authentication facts, GeoIP lookup, bounded request buffering, and response construction. Training and management still have Python interfaces.
Install the explicit native adapter instead of the existing AIWAF middleware chain. Installing the required Rust dependency does not automatically switch existing applications to this pipeline. Legacy adapters remain available for custom stores and hooks; their configuration and fallback behavior are separate.
Two engine calls surround application execution: begin enforces request checks; finish observes the response and writes state/logs. Java remains native Java; Node/WASM does not expose Python filesystem CSV bindings.
Continue with the request lifecycle, the native profile, migration, and performance and deployment.
