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) = 0forn <= 1c(n) = 1forn = 2- otherwise
c(n) = 2 * (ln(n-1) + 0.5772156649) - 2*(n-1)/n
Interpretation:
- Higher
s(x)means more anomalous. score_samplesreturns the opposite of the anomaly score (higher = more normal), like sklearn.decision_function = score_samples - offset_.predictreturns1for inliers and-1for outliers.- With
contamination="auto",offset_ = -0.5. With numeric contamination,offset_is set to the percentile of training scores.
Retraining:
- With
warm_start=True,fitappends new trees up ton_estimators. retrainalways 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.publishedworkflow_dispatch
The workflow builds:
- Wheels for Python
3.8to3.12onubuntu-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.minorbetweenaiwafandaiwaf-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.tomlis the source of Python package metadataCargo.tomlis the source of Rust crate metadata
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5435ca96adb7e5006e8c18c08072f9149653deb0e4f1da76e11eab8f5551b0b5
|
|
| MD5 |
1dcc0334ef7aa5f93361b7826a68321a
|
|
| BLAKE2b-256 |
194ffcb60c748cb6e806a549c7eceae1bc5523a1e91c16a9b97c168ec45d4ba1
|
Provenance
The following attestation bundles were made for aiwaf_rust-0.1.2.tar.gz:
Publisher:
publish.yml on aiwaf-project/aiwaf-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiwaf_rust-0.1.2.tar.gz -
Subject digest:
5435ca96adb7e5006e8c18c08072f9149653deb0e4f1da76e11eab8f5551b0b5 - Sigstore transparency entry: 1280157057
- Sigstore integration time:
-
Permalink:
aiwaf-project/aiwaf-rust@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/aiwaf-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Trigger Event:
workflow_dispatch
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e1e938908a7b2f30a5dd1f70dd310c02e698575874c7abcda4ad4b14fe748f4
|
|
| MD5 |
49c0a3ea5bb212fb6e0f3c26efb22ab4
|
|
| BLAKE2b-256 |
438d954501d25268fe99735acce0b081351efc3d4ba42a8da37ebede6609d8d8
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiwaf_rust-0.1.2-cp38-abi3-win_amd64.whl -
Subject digest:
6e1e938908a7b2f30a5dd1f70dd310c02e698575874c7abcda4ad4b14fe748f4 - Sigstore transparency entry: 1280157063
- Sigstore integration time:
-
Permalink:
aiwaf-project/aiwaf-rust@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/aiwaf-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 1.0 MB
- Tags: CPython 3.8+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
609ec9711f9e1788c690ef18f22412e35303c6addba99ab10dc3ecba713f021d
|
|
| MD5 |
14e1a162c425137a20aa9138a5489a81
|
|
| BLAKE2b-256 |
759d07a464eb63fed7bfcdbd4e98648bee8c4b9ae5fc6f54bc737ca2dd25149c
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiwaf_rust-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
609ec9711f9e1788c690ef18f22412e35303c6addba99ab10dc3ecba713f021d - Sigstore transparency entry: 1280157065
- Sigstore integration time:
-
Permalink:
aiwaf-project/aiwaf-rust@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/aiwaf-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 870.7 kB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c3a21ab520c9acaa2b86653a7527895e682ef8141126c2e28430eb86539db2c
|
|
| MD5 |
1b5c5eb4a156217dd6d51a03a8f9e0ae
|
|
| BLAKE2b-256 |
7cdec2fb4308f655375c50968fb7fc045c7fcfe958819669c38be53101c7ac8c
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiwaf_rust-0.1.2-cp38-abi3-macosx_11_0_arm64.whl -
Subject digest:
0c3a21ab520c9acaa2b86653a7527895e682ef8141126c2e28430eb86539db2c - Sigstore transparency entry: 1280157059
- Sigstore integration time:
-
Permalink:
aiwaf-project/aiwaf-rust@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/aiwaf-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d53c5bee7e003b50a5ae01e799d7774038ff1300 -
Trigger Event:
workflow_dispatch
-
Statement type: