Jwt Cracking in Actix
How JWT Cracking Manifests in Actix
JWT cracking in Actix applications typically stems from improper configuration of JWT validation middleware or custom extraction logic. Actix developers often use crates like jsonwebtoken or actix-web-httpauth to handle bearer tokens. Vulnerabilities arise when:
- Weak or hardcoded secrets are used in
DecodingKey::from_secretwithout environment variable separation. - Algorithm confusion is allowed, such as accepting the
nonealgorithm or failing to enforce a specific algorithm (e.g., allowing both HS256 and RS256). - Critical claims are not validated, such as
exp(expiration),nbf(not before), oriss(issuer). - Token extraction is bypassed by handlers that manually parse Authorization headers without reusing validated middleware context.
A vulnerable Actix handler might look like this:
use actix_web::{web, HttpResponse, Responder};
use jsonwebtoken::{decode, DecodingKey, Validation};
#[post("/admin")]
pub async fn admin_endpoint(
auth_header: web::Header
) -> impl Responder {
// Extract token from "Bearer "
let token = auth_header.trim_start_matches("Bearer ");
// VULNERABLE: No algorithm enforcement, weak secret
let decoding_key = DecodingKey::from_secret(b"secret123");
let mut validation = Validation::default();
validation.validate_exp = false; // Disables expiration check
match decode::<serde_json::Value>(token, &decoding_key, &validation) {
Ok(_) => HttpResponse::Ok().body("Admin access"),
Err(_) => HttpResponse::Unauthorized().body("Invalid token"),
}
} Here, validation.validate_exp = false disables expiration checks, and the secret is hardcoded and weak. An attacker can crack short secrets using brute-force tools like john or hashcat (e.g., CVE-2020-28052 relates to JWT secret cracking in various libraries). In Actix, if the same secret is used across environments, offline cracking becomes feasible.
Actix-Specific Detection
middleBrick detects JWT cracking vulnerabilities by actively testing unauthenticated endpoints. For Actix applications, it performs:
- Algorithm confusion tests: Sending tokens with
alg: noneor mismatched signatures to bypass verification. - Secret strength assessment: If the scanner can infer a secret (e.g., from default configs or weak patterns), it attempts dictionary attacks on captured tokens.
- Claim validation bypass: Submitting tokens with missing or invalid
exp,nbf, orissto see if the Actix endpoint accepts them. - Token extraction path analysis: Checking if endpoints manually parse tokens without middleware, potentially missing validation.
Using middleBrick's CLI, you can scan an Actix API endpoint:
middlebrick scan https://api.youractixapp.comThe scan takes 5–15 seconds and returns a risk score (0–100) with per-category breakdowns. For JWT issues, the report highlights:
| Check | What middleBrick Tests | Actix-Specific Indicator |
|---|---|---|
| Authentication | Algorithm confusion, weak secrets | Endpoint accepts none algorithm or short secrets (secret, password) |
| Input Validation | Claim validation bypass | 200 OK response with expired token or missing iss |
middleBrick's OpenAPI/Swagger analysis also cross-references your spec's security schemes (e.g., type: http, scheme: bearer) with runtime behavior. If your spec defines JWT bearer tokens but runtime accepts unsigned tokens, that's a critical mismatch. The GitHub Action can enforce that no JWT-related findings appear before merge:
uses: middlebrick/github-action@v1
with:
api_url: ${{ secrets.API_URL }}
fail_on_score_below: 90Actix-Specific Remediation
Fix JWT cracking vulnerabilities in Actix by using robust, configured middleware. The actix-web-httpauth crate provides a bearer middleware that enforces algorithm and claim validation. Here's a secure setup:
use actix_web::{web, App, HttpServer, HttpResponse};
use actix_web_httpauth::bearer::{BearerAuth, Config};
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
use std::env;
fn validate_token(token: &str) -> Result<serde_json::Value, HttpResponse> {
// Load secret from environment (never hardcode)
let secret = env::var("JWT_SECRET")
.map_err(|_| HttpResponse::InternalServerError().body("Server config error"))?;
// Enforce RS256 (or HS256 with strong secret)
let decoding_key = DecodingKey::from_secret(secret.as_bytes());
let mut validation = Validation::new(Algorithm::HS256);
validation.validate_exp = true; // Enforce expiration
validation.required_spec_claims = vec!["exp", "iss"].into_iter().collect();
validation.iss = Some("your-issuer".to_string());
decode::<serde_json::Value>(token, &decoding_key, &validation)
.map(|data| data.claims)
.map_err(|_| HttpResponse::Unauthorized().body("Invalid token"))
}
#[get("/secure")]
async fn secure_endpoint(
auth: BearerAuth,
) -> Result<HttpResponse, HttpResponse> {
let token = auth.token();
let _claims = validate_token(token)?;
Ok(HttpResponse::Ok().body("Secure data"))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(
web::scope("/api")
.service(secure_endpoint)
.wrap(
// Optional: Global bearer middleware with custom config
BearerAuth::new(Config::default())
)
)
})
.bind("0.0.0.0:8080")?
.run()
.await
}Key fixes:
- Secret management: Use
env::var("JWT_SECRET")with a strong, randomly generated secret (minimum 256-bit for HS256). In production, integrate with vaults (e.g., HashiCorp Vault) via middleware. - Algorithm enforcement:
Validation::new(Algorithm::HS256)rejects tokens with other algorithms, preventing confusion attacks. - Claim validation:
validation.validate_exp = trueandrequired_spec_claimsensureexp,iss, etc., are present and valid. - Centralized validation: The
validate_tokenfunction is reused, avoiding manual parsing in handlers.
For asymmetric algorithms (RS256/ES256), use DecodingKey::from_rsa_pem with a public key file, never a secret. Also, set validation.leeway = 0 to avoid time-skipping attacks. After applying fixes, rescan with middleBrick to confirm the JWT issue is resolved and your security score improves.