Spring4shell in Actix with Bearer Tokens
Spring4shell in Actix with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Spring4shell (CVE-2022-22965) is a remote code execution vulnerability in Spring Framework affecting versions prior to 5.3.18 and 5.2.x prior to 5.2.19, involving data binding via the ClassValue field in JDK 9+ that can be triggered through crafted HTTP requests. When an Actix web service is built on vulnerable Spring dependencies and exposes endpoints that accept user-supplied data for model binding, the attack surface expands if authentication is delegated to Bearer Tokens handled at the application layer.
In a typical Actix setup using Bearer Tokens, the token is often read from an Authorization header, validated asynchronously, and then attached to the request extensions or session state for downstream authorization checks. Because Actix relies on Rust-based routing and extractors, the immediate risk from Spring4shell is not in Actix itself but in any proxied or embedded Spring component (e.g., an API gateway or backend service) that receives the request and performs data binding on query parameters, JSON payloads, or form fields without proper constraints.
Bearer Tokens in this context can inadvertently become part of the data binding path if the token value is copied into a command object or used to dynamically select a service endpoint that then forwards user-controlled input to a vulnerable Spring application. For example, if an Actix handler extracts the Bearer Token, places it into a request structure, and forwards parameters to a downstream Spring microservice, the token may be reflected in logs or used to select a target that processes untrusted data with insecure data binding. This indirect exposure means the presence of Bearer Tokens does not introduce the vulnerability but can influence how an attacker chains authorization context with data manipulation to reach a vulnerable endpoint.
The practical risk pattern involves an unauthenticated or low-privilege attacker sending a request with a manipulated parameter (e.g., class.module.classLoader.resources.context.pipeline.first.valve) while including a valid Bearer Token obtained through prior reconnaissance. If the downstream service incorrectly binds request fields to sensitive classes, the exploit can lead to arbitrary code execution. middleBrick scans this combined surface by testing unauthenticated attack paths and also probing authenticated flows when Bearer Tokens are supplied, checking for improper authorization across properties and input validation gaps.
To detect this combination, middleBrick runs 12 parallel checks including Input Validation, Authorization (BOLA/IDOR), and Property Authorization. When scanning an API that uses Bearer Tokens, you can use the CLI to submit the endpoint and provide a token via environment variables, enabling the scanner to exercise authenticated-aware paths. The report will highlight whether any endpoint allows overprivileged binding or exposes dangerous classloader-related parameters without requiring elevated credentials.
Bearer Tokens-Specific Remediation in Actix — concrete code fixes
Remediation centers on ensuring Bearer Tokens are treated as opaque credentials, never bound to mutable request models, and that downstream services enforce strict input validation and type-safe extraction. Below are concrete Actix-based examples that demonstrate secure handling.
1. Secure Bearer Token extraction and forwarding
Extract the token without copying it into data-bound structures. Use extractors to isolate authorization from business data.
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct ApiRequest {
query_param: String,
// Do NOT include token fields here
}
async fn handler(
req: HttpRequest,
body: web::Json,
) -> impl Responder {
// Extract Bearer Token separately
let token = match req.headers().get("Authorization") {
Some(h) => h.to_str().unwrap_or("").strip_prefix("Bearer ").unwrap_or(""),
None => return HttpResponse::Unauthorized().finish(),
};
// Forward to downstream service without embedding token in payload
let client = reqwest::Client::new();
let upstream_resp = client
.post("http://spring-service/api/action")
.bearer_auth(token)
.json(&body.into_inner())
.send()
.await;
match upstream_resp {
Ok(r) => HttpResponse::Ok().body(r.text().await.unwrap_or_default()),
Err(_) => HttpResponse::BadGateway().finish(),
}
}
2. Avoid dynamic class selection based on user input
Ensure that any parameter used to select services or deserialization targets is enumerated and validated. Never allow raw strings to dictate class loading paths.
use actix_web::web;
async fn safe_action(payload: web::Json) -> HttpResponse {
let action = payload.get("action")
.and_then(|v| v.as_str())
.unwrap_or("");
// Whitelist allowed actions
match action {
"create" | "update" | "delete" => {
// Proceed with validated action
HttpResponse::Ok().body("processed")
}
_ => HttpResponse::BadRequest().body("invalid action"),
}
}
3. Enforce strict schema validation on incoming JSON
Use strongly typed structures and reject unexpected fields to reduce binding surface.
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
struct StrictPayload {
query_param: String,
#[serde(rename = "type")]
kind: String,
}
async fn typed_handler(body: web::Json) -> HttpResponse {
// body is guaranteed to match the schema
HttpResponse::Ok().json(&*body)
}
When integrating with a dashboard or CI/CD, the middleBrick CLI can validate these patterns by scanning endpoints with and without tokens. The Pro plan supports continuous monitoring and GitHub Action integration, so any regression in input handling or authorization mapping can fail builds before deployment.