AIWAF Python

Source and package versions

One AIWAF repository. Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/. Source and canonical README. Versions shown are the latest published releases; each package is versioned independently. Current versions 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.

Python 1.1.8 lives in py/aiwaf/. Install a framework extra for Django, Flask, or FastAPI. The package installs its required aiwaf-rust>=0.2.7 runtime. The package metadata declares Python 3.10 or newer; the selected framework and scientific dependencies may require a newer interpreter.

Packages in the monorepo

Each package is versioned and released independently.

RuntimePackagePublished versionPrimary use
Pythonaiwaf1.1.8Django, Flask, and FastAPI protection
Node.jsaiwaf1.1.5Express and Node framework middleware
Rust/Pythonaiwaf-rust0.2.7Native Python acceleration and JSON model inference
WebAssemblyaiwaf-wasm0.2.5Rust detection and model primitives for JavaScript
Javaio.github.aiwaf-project:aiwaf-java1.3.5Spring MVC and Jakarta Servlet protection

Supported framework integrations include Django, Flask, FastAPI, Express, Fastify, Hapi, Koa, NestJS, Next.js API routes, AdonisJS, Sails.js, Spring MVC, and Jakarta Servlet.

Repository layout

.
├── py/aiwaf/                       Python package and adapters
├── js/                             Node.js package and adapters
├── rust/                           Rust core and Python bindings
│   └── crates/aiwaf_wasm/          WebAssembly bindings
├── java/                           Java 17 package
├── tests/                          Python integration and parity tests
├── examples/                       Focused Python examples
├── .github/workflows/              Tests, security checks, and releases
├── README.md                       Canonical project documentation
└── LICENSE                         Canonical Elastic License 2.0 (see NOTICE)

Request controls

  • IP blocklist, exemption, reputation, expiry, and progressive-block handling
  • Sliding-window rate limiting and flood detection
  • Header, method, request-size, content-type, and parameter validation
  • Static and learned malicious keyword detection
  • Honeypot field and form-timing checks
  • UUID probing and tamper detection
  • GeoIP allow/block policies using the bundled MMDB data
  • Route manifests, path-specific overrides, and decorator/annotation exemptions
  • Memory, file, CSV, SQLite, database, and cache-backed runtime state, depending on the runtime
  • Structured request logging and offline training
  • Six-feature anomaly models with Rust, JavaScript, and Java implementations
  • Optional Rust acceleration for Python and optional WebAssembly acceleration for Node.js

The runtimes share policy intent and training feature names, but their framework adapters and model implementations remain language-native. Model artifacts are not generally interchangeable across languages.

Continue

Rust-owned CSV request pipeline

Current release: this page documents Python 1.1.8 and Rust/Python 0.2.7, both published on PyPI. Python 1.1.8 requires aiwaf-rust>=0.2.7; framework dependencies remain extras.

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.

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.

Continue with the request lifecycle, the native profile, migration, and performance and deployment.

Shared Python CSV storage

List APIs and command help now use blocklist and allowlist. Earlier import/method/command spellings remain compatibility aliases. Existing CSV filenames and Django model identity are retained so upgrades preserve stored blocks and exemptions; use the package storage constants rather than constructing filenames.

Python 1.1.4 standardizes Flask, FastAPI, Django CSV mode, and the explicit native pipeline on blacklist.csv, whitelist.csv, keywords.csv, geo_blocked_countries.csv, and path_exemptions.csv. Keyword frequencies and non-policy runtime history are retained in runtime_metadata.csv. Memory, JSON-file, database, and Django ORM modes keep their existing storage behavior.

IntegrationCSV directory configuration
Legacy FlaskSet app.config['AIWAF_USE_CSV'] = True and app.config['AIWAF_DATA_DIR'] before initializing AIWAF.
Legacy DjangoSet AIWAF_STORAGE_MODE = "csv" and AIWAF_DATA_DIR in project settings.
Legacy FastAPIPass storage={"backend": "csv", "data_dir": "/absolute/path/aiwaf_data"} to AIWAF. Its default backend remains memory.
Native adaptersPass the lowercase data_dir in the dedicated native profile. Native adapters do not inherit legacy framework settings.

Startup imports legacy runtime CSV data once, preserving block expiry and metadata. Original sources remain intact; backups and completion markers support recovery and prevent removed entries from returning on restart. Existing canonical policy wins conflicts. Stop old workers before upgrading and use the same absolute directory for the application and CLI. See migration paths and recovery.

Flask management searches existing project aiwaf_data and .aiwaf/data before user/package directories. Explicit AIWAF_DATA_DIR or --data-dir takes priority. The five policy files use UTF-8 across Python and Rust. Sharing these files does not make memory rate buckets, model history, or optional memory form timing distributed.

Flask and FastAPI native honeypot cache

Python 1.1.8 with aiwaf-rust 0.2.7 adds opt-in Redis and supplied-cache timing to both native adapters. CSV remains their default. Rust retains timing rules and exemptions; only timestamp I/O uses the cache.

import os
profile = {
    "data_dir": "aiwaf_data",
    "honeypot_backend": "redis",
    "honeypot_redis_url": os.environ["AIWAF_REDIS_URL"],
    "honeypot_cache_namespace": "myapp:honeypot:v1",
}
# Flask:
from aiwaf.flask.csv_pipeline import NativeAIWAF
NativeAIWAF(app, config=profile)
# FastAPI alternative:
# from aiwaf.fast.csv_pipeline import NativeAIWAFMiddleware
# app.add_middleware(NativeAIWAFMiddleware, config=profile)

For Flask-Caching or a compatible custom object, use honeypot_backend="cache" and pass honeypot_cache=cache to the native adapter. It must provide synchronous get(key) and set(key, value, timeout=seconds), preserve the timestamp/expiry pair, honor TTL and propagate errors. A false write result means failure; silent/no-op backends are unsuitable. Local caches remain worker-local. Use a shared backend and the same namespace across workers; isolate unrelated applications with different namespaces.

Records have a 300-second TTL. Missing/evicted timestamps allow the timing check, while cache errors and invalid records return generic HTTP 503. Expired-page POSTs return 409 until a new GET or TTL expiry; old snapshots are not deleted. FastAPI runs cache-backed native checks in its worker thread pool so synchronous cache I/O does not block the event loop. Other policy stores and legacy middleware behavior are unchanged.

Django native honeypot cache

Python 1.1.8 with aiwaf-rust 0.2.7 defaults Django native honeypot timing to Django's configured cache. Set honeypot_cache_alias in AIWAF_CSV_PIPELINE to select an alias; it defaults to default. Rust calls a small Python cache adapter for timestamp I/O and retains timing decisions, logical expiry and exemptions. Other policy CSVs and rate-limit configuration are unchanged.

AIWAF_CSV_PIPELINE = {
    "data_dir": "aiwaf_data",
    "honeypot_cache_alias": "default",
}
# Configure CACHES["default"] with a shared backend for multiple workers.

Redis or Memcached can share timestamps across workers. LocMemCache is supported with a startup warning; it remains worker-local. DummyCache is rejected when honeypot protection is enabled. Cache errors, failed writes and invalid records produce generic HTTP 503; known ignored-cache-error modes are rejected.

Entries use a 300-second TTL. Expired-page POSTs return 409 until a new GET or TTL expiry. No eager deletion occurs, so an old POST cannot erase a concurrent refresh. A missing or evicted timestamp allows the POST timing check, as before; cache failure is not treated as a miss. Backends do not transfer existing timestamps. Install the matching Rust extension and restart workers together.

Explicit honeypot_backend="csv" retains filesystem timing; "memory" uses Rust's per-engine map. Flask, FastAPI and direct native construction keep CSV as the default. See the Django cache documentation.

Training replay protection

Python 1.1.6 with aiwaf-rust 0.2.5 uses Rust-owned receipts in Flask, FastAPI, and Django. Reusing requests already handled by training cannot extend or recreate a block. Fresh requests must independently satisfy enforcement rules; models and keyword learning can still reuse historical logs.

Keep training_evidence.json across expiry, manual unblocking, log rotation, and restarts. It lives in the policy data directory unless AIWAF_TRAINING_STATE_DIR selects another durable directory. Trainers sharing a blocklist must share that directory. Receipts start with this release and cannot reconstruct decisions made by older versions. Missing native support and corrupt state stop training visibly. Block and receipt writes are separate, so a crash between them can require recovery.

Flask CLI listing now filters expired entries without rewriting an older snapshot over blocks concurrently added or refreshed by a trainer. The CLI displays the canonical added_date, with the older timestamp as a fallback. This listing fix and training replay protection address different causes of block changes. A first temporary block defaults to 900 seconds; later reputation decisions can increase its duration. Check the stored expiry rather than assuming every block lasts 24 hours.