Skip to main content

Rust-powered WAF heuristics exposed to Python via PyO3

Project description

aiwaf-rust

aiwaf-rust is a Rust core with Python and WebAssembly bindings that provides fast request-header, behavior heuristics, and isolation forest anomaly scoring for WAF-style detection.

  • PyPI package: aiwaf-rust
  • Python import: aiwaf_rust
  • Built with: PyO3 + maturin
  • WASM package: aiwaf-wasm (npm)
  • Built with: wasm-bindgen + wasm-pack

Features

  • Header validation with configurable required headers and scoring
  • Request feature extraction for downstream detection logic
  • Recent behavior analysis for suspicious scanning patterns
  • Isolation Forest anomaly detection with sklearn-style API
  • Cross-platform wheel publishing (Linux, macOS, Windows)
  • WASM build for browser and bundler targets

Installation

From PyPI

pip install aiwaf-rust

Local development install

pip install maturin
maturin develop

Python API

import aiwaf_rust

# 1) Basic header validation
reason = aiwaf_rust.validate_headers({
    "HTTP_USER_AGENT": "Mozilla/5.0",
    "HTTP_ACCEPT": "text/html"
})

# 2) Configurable validation
reason = aiwaf_rust.validate_headers_with_config(
    {
        "HTTP_USER_AGENT": "Mozilla/5.0",
        "HTTP_ACCEPT": "text/html"
    },
    ["HTTP_USER_AGENT", "HTTP_ACCEPT"],
    3,
)

# 3) Feature extraction
features = aiwaf_rust.extract_features(
    {
        "ip": "1.2.3.4",
        "path_lower": "/wp-admin",
        "path_len": 9,
        "timestamp": 1700000000.0,
        "response_time": 0.03,
        "status_idx": 3,
        "kw_check": True,
        "total_404": 5,
    },
    []
)

# 4) Behavior analysis
analysis = aiwaf_rust.analyze_recent_behavior([], "1.2.3.4")

# 5) Isolation Forest
forest = aiwaf_rust.IsolationForest(
    n_estimators=100,
    max_samples="auto",
    contamination="auto",
    max_features=1.0,
    bootstrap=False,
    random_state=42,
    warm_start=False,
)
forest.fit([[0.1, 1.0], [0.2, 1.1], [9.0, 9.0]])
score = forest.anomaly_score([9.0, 9.0])
labels = forest.predict([[0.1, 1.0], [9.0, 9.0]])

# Save and load
state = forest.to_json()
forest2 = aiwaf_rust.IsolationForest.from_json(state)
forest2.retrain([[0.15, 1.05], [0.25, 1.2]])

WASM API (JS)

Install from npm:

npm install aiwaf-wasm

Usage (bundler target):

import init, { IsolationForest, validate_headers, extract_features } from "aiwaf-wasm";

await init();

const reason = validate_headers({
  HTTP_USER_AGENT: "Mozilla/5.0",
  HTTP_ACCEPT: "text/html",
});

const feats = extract_features([
  {
    ip: "1.2.3.4",
    path_lower: "/wp-admin",
    path_len: 9,
    timestamp: 1700000000.0,
    response_time: 0.03,
    status_idx: 3,
    kw_check: true,
    total_404: 5,
  },
], []);

const forest = new IsolationForest({
  n_estimators: 100,
  max_samples: "auto",
  contamination: "auto",
  max_features: 1.0,
  bootstrap: false,
  random_state: 42,
  warm_start: false,
});
forest.fit([[0.1, 1.0], [0.2, 1.1], [9.0, 9.0]]);
const score = forest.anomaly_score([9.0, 9.0]);
const state = forest.to_json();
const forest2 = IsolationForest.from_json(state);
forest2.retrain([[0.15, 1.05], [0.25, 1.2]]);

Isolation Forest Details

Isolation Forest isolates points by randomly choosing a feature and a split value between that feature’s min and max. The number of splits required to isolate a point is its path length. Anomalies tend to have shorter path lengths because they are easier to isolate.

Key mechanics:

  • A tree is built by selecting a random split value for each candidate feature at a node and choosing the split with the best variance reduction (ExtraTreeRegressor-style random splitter).
  • The tree stops when it reaches max_depth = ceil(log2(max_samples)) or the node has 0 or 1 samples, or all values are identical for the chosen feature.
  • Path length for a point is the depth at which it lands, plus the average path length adjustment for the leaf size.

Scoring:

  • For each tree, compute the path length h(x).
  • Average across trees: E[h(x)].
  • Convert to anomaly score: s(x) = 2 ^ (-E[h(x)] / c(max_samples)).
  • c(n) is the average path length of an unsuccessful search in a binary search tree:
    • c(n) = 0 for n <= 1
    • c(n) = 1 for n = 2
    • otherwise c(n) = 2 * (ln(n-1) + 0.5772156649) - 2*(n-1)/n

Interpretation:

  • Higher s(x) means more anomalous.
  • score_samples returns the opposite of the anomaly score (higher = more normal), like sklearn.
  • decision_function = score_samples - offset_.
  • predict returns 1 for inliers and -1 for outliers.
  • With contamination="auto", offset_ = -0.5. With numeric contamination, offset_ is set to the percentile of training scores.

Retraining:

  • With warm_start=True, fit appends new trees up to n_estimators.
  • retrain always appends trees, preserving existing ones.

Build and Test

# Run Rust tests
cargo test

# Build Python wheel locally
maturin build --release --out dist

# Build source distribution
maturin sdist --out dist

# Build WASM package
cd crates/aiwaf_wasm
wasm-pack build --release --target bundler

Publishing

Publishing is handled by GitHub Actions using trusted publishing.

Workflow: .github/workflows/publish.yml

Trigger conditions:

  • release.published
  • workflow_dispatch

The workflow builds:

  • Wheels for Python 3.8 to 3.12 on ubuntu-latest, macos-latest, windows-latest
  • One source distribution (sdist)

Then it publishes to PyPI using:

  • pypa/gh-action-pypi-publish@release/v1
  • OIDC (id-token: write)

Compatibility Policy

aiwaf-rust and aiwaf should be versioned together when possible.

Recommended policy:

  • Match major.minor between aiwaf and aiwaf-rust
  • Use patch versions independently for bug fixes
  • Document compatibility here when versions diverge
aiwaf aiwaf-rust
0.1.x 0.1.x

Development Notes

  • Module name in Rust and Python is aiwaf_rust
  • pyproject.toml is the source of Python package metadata
  • Cargo.toml is the source of Rust crate metadata

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiwaf_rust-0.1.2.tar.gz (32.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl (701.9 kB view details)

Uploaded CPython 3.8+Windows x86-64

aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.34+ x86-64

aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl (870.7 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

File details

Details for the file aiwaf_rust-0.1.2.tar.gz.

File metadata

  • Download URL: aiwaf_rust-0.1.2.tar.gz
  • Upload date:
  • Size: 32.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aiwaf_rust-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5435ca96adb7e5006e8c18c08072f9149653deb0e4f1da76e11eab8f5551b0b5
MD5 1dcc0334ef7aa5f93361b7826a68321a
BLAKE2b-256 194ffcb60c748cb6e806a549c7eceae1bc5523a1e91c16a9b97c168ec45d4ba1

See more details on using hashes here.

Provenance

The following attestation bundles were made for aiwaf_rust-0.1.2.tar.gz:

Publisher: publish.yml on aiwaf-project/aiwaf-rust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 701.9 kB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6e1e938908a7b2f30a5dd1f70dd310c02e698575874c7abcda4ad4b14fe748f4
MD5 49c0a3ea5bb212fb6e0f3c26efb22ab4
BLAKE2b-256 438d954501d25268fe99735acce0b081351efc3d4ba42a8da37ebede6609d8d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl:

Publisher: publish.yml on aiwaf-project/aiwaf-rust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 609ec9711f9e1788c690ef18f22412e35303c6addba99ab10dc3ecba713f021d
MD5 14e1a162c425137a20aa9138a5489a81
BLAKE2b-256 759d07a464eb63fed7bfcdbd4e98648bee8c4b9ae5fc6f54bc737ca2dd25149c

See more details on using hashes here.

Provenance

The following attestation bundles were made for aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl:

Publisher: publish.yml on aiwaf-project/aiwaf-rust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0c3a21ab520c9acaa2b86653a7527895e682ef8141126c2e28430eb86539db2c
MD5 1b5c5eb4a156217dd6d51a03a8f9e0ae
BLAKE2b-256 7cdec2fb4308f655375c50968fb7fc045c7fcfe958819669c38be53101c7ac8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on aiwaf-project/aiwaf-rust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page