Skip to content

axum-guard-rs

axum-guard-rs is application-layer security middleware for axum, powered by the guard-core-rs detection engine. It is part of the Guard ecosystem.

The crate is the thin axum-facing surface over tower-guard-rs: axum routers are tower services, so Router::layer with the generic GuardLayer is the whole integration. The with_guard constructor, the re-exports an axum application needs, and axum-specific tests pin the behavior against axum::body::Body. Per the ecosystem boundary rules this crate contains no security logic: detection comes from the engine, request screening from tower-guard-rs.

Ecosystem position

guard-core (Python)           <- Reference implementation, spec owner
├── guard-core-rs             <- Rust engine: detection, preprocessing, semantics
│   ├── tower-guard-rs        <- Adapter: tower middleware
│   ├── axum-guard-rs         <- Adapter: axum layer over tower-guard-rs (this repo)
│   ├── actix-guard-rs        <- Adapter: actix-web middleware
│   └── rocket-guard-rs       <- Adapter: rocket fairing and guards
├── guard-core-go             <- Go port
└── guard-core-ts             <- TypeScript port

The guard translates native request content into engine inputs (path, query string, header values, buffered body), runs one engine call per request view, and translates a threat verdict into a native block response. The adapter is fail-secure: any failure to complete the security check answers 500, never an uninspected passthrough.

Installation

cargo add axum-guard-rs

The published crate is 1.0.0 and depends on the published tower-guard-rs 1.0.0, itself pinned to guard-core-engine 4.0.4. Requires Rust 1.92 or later (edition 2024) and axum 0.8. See Installation for details.

Quick start

use axum::Router;

let app = Router::new()
    .route("/", axum::routing::get(|| async { "hello" }))
    .layer(axum_guard_rs::with_guard(axum_guard_rs::default_config()));

Apply the layer with Router::layer (every registered route) or Router::route_layer (routes only, skipping the fallback).

What it inspects

One engine call per request view:

Request part Engine context Notes
Path url_path Skipped for /
Query string query_param Skipped when empty
Header values header Skips sec-* and the negotiation/routing headers
Body request_body Buffered first, capped (262 144 bytes by default)

The HTTP method is not scanned.

Responses

Situation Status Body
Engine flags a view 400 Bad Request Suspicious activity detected
Body exceeds the cap 413 Payload Too Large Payload too large
Body read error or engine panic 500 Internal Server Error Security check failed

Where to go next

  • Installation for requirements and dependency setup
  • API for the full public surface and behavior tables
  • Examples for runnable applications