Cross Site Request Forgery in Axum with Jwt Tokens
Cross Site Request Forgery in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Cross Site Request Forgery (CSRF) in Axum with Jwt Tokens can occur when authentication relies solely on bearer tokens stored in a way that browsers automatically include in cross-origin requests. Jwt Tokens are commonly stored in browser storage or cookies; if your Axum application uses cookie-based storage for JWTs and does not enforce strict anti-CSRF protections, a malicious site can trigger authenticated state-changing requests on behalf of a user.
Unlike traditional session cookies, Jwt Tokens do not automatically protect against CSRF; the burden shifts to developers to ensure tokens are not sent cross-origin unintentionally. When Axum endpoints accept Jwt Tokens from cookies and do not validate the origin or require explicit anti-CSRF tokens, an attacker can craft a form or script on a different domain that performs actions via the user’s authenticated session. This is especially relevant when CORS is misconfigured to allow credentials or broad origins, allowing a crafted request to succeed with the user’s Jwt Token.
An example attack chain: a user is authenticated to an Axum API with a Jwt Token stored in an HttpOnly cookie. The user visits a malicious site that contains an image tag or fetch request pointing to the vulnerable Axum endpoint that changes an email or initiates a transfer. If the Axum service does not check the Origin header or require a custom header that cannot be set cross-origin, the browser includes the Jwt Token automatically, and the request succeeds without user consent. This exposes state-changing methods to CSRF even when Jwt Tokens are used for authentication.
In the context of the 12 security checks run by middleBrick, CSRF related findings often surface alongside CORS and Authentication misconfigurations. The scanner tests whether endpoints that accept Jwt Tokens also implement origin validation or anti-CSRF mechanisms when cookies are involved. This helps identify whether an unauthenticated or low-privilege attacker can induce authenticated actions via cross-origin requests.
For reference, related real-world attack patterns include OWASP CSRF and CORS misconfigurations documented in the OWASP API Security Top 10. middleBrick’s scans correlate these findings with your API’s runtime behavior, providing prioritized guidance to reduce exposure without relying on assumptions about framework defaults.
Jwt Tokens-Specific Remediation in Axum — concrete code fixes
To remediate CSRF when using Jwt Tokens in Axum, implement strict origin validation, require custom headers for state-changing requests, and avoid automatically sending Jwt Tokens cross-origin. Below are concrete code examples demonstrating secure patterns in Axum.
1. Validate Origin and Referer headers on sensitive endpoints:
use axum::{
async_trait,
extract::Request,
middleware::Next,
response::Response,
};
use std::convert::Infallible;
async fn cors_middleware(
request: Request,
next: Next,
) -> Result<Response, Infallible> {
let origin = request.headers().get("origin").and_then(|v| v.to_str().ok());
let allowed_origins = ["https://your-trusted-frontend.com"];
if let Some(orig) = origin {
if allowed_origins.contains(&orig) {
let mut response = next.run(request).await;
response.headers_mut().insert(
"access-control-allow-origin",
orig.parse().unwrap(),
);
response.headers_mut().insert(
"access-control-allow-credentials",
"true".parse().unwrap(),
);
return Ok(response);
}
}
Ok(Response::builder().status(403).body(hyper::Body::empty()).unwrap())
}
This middleware ensures that only requests from your trusted frontend origin are processed, reducing the risk of CSRF via cross-origin requests that include Jwt Tokens.
2. Require a custom header (e.g., X-Requested-With) for state-changing methods and avoid automatic cookie inclusion:
use axum::{
extract::{Header, State},
http::StatusCode,
response::IntoResponse,
};
async fn change_email_handler(
State(_state): State<AppState>,
Header(req_x_requested_with): Header<String>,
) -> Result<impl IntoResponse, StatusCode> {
const EXPECTED: &str = "XMLHttpRequest";
if req_x_requested_with != EXPECTED {
return Err(StatusCode::FORBIDDEN);
}
// proceed with email change logic
Ok((StatusCode::OK, "Email updated"))
}
By requiring a custom header, you ensure that browser-based CSRF attacks cannot trigger these endpoints because JavaScript from a malicious site cannot set this header due to CORS restrictions.
3. Store Jwt Tokens securely and avoid cookie-based storage for authentication when possible. If you must use cookies, set SameSite=Strict or Lax and Secure flags:
use axum::response::SetCookie;
let cookie = format!(
"jwt={}; Path=/; Secure; HttpOnly; SameSite=Strict",
token
);
axum::response::Response::builder()
.header(axum::http::header::SET_COOKIE, cookie)
.body(hyper::Body::empty())
.unwrap();
SameSite=Strict prevents the browser from sending the Jwt Token in cross-site requests, mitigating CSRF while still allowing first-party authenticated requests. Combine this with CORS policies that do not expose credentials to untrusted origins.
4. When using middleBrick, verify that your endpoints requiring Jwt Tokens also enforce origin checks and do not rely on permissive CORS settings. The scanner’s findings will highlight mismatches between your authentication scheme and runtime request patterns, enabling targeted fixes like those shown above.