HIGH data exposureactixbearer tokens

Data Exposure in Actix with Bearer Tokens

Data Exposure in Actix with Bearer Tokens — how this specific combination creates or exposes the vulnerability

In Actix web applications, bearer tokens are commonly passed in the Authorization header as Bearer <token>. When authorization logic is incomplete or misapplied, responses can inadvertently include sensitive data such as user profiles, internal identifiers, or secondary tokens. Data Exposure findings in middleBrick scans highlight cases where authenticated or unauthenticated endpoints return more information than intended, particularly when route guards or permission checks are missing or inconsistently applied.

Actix does not automatically enforce per-route authorization based on token scopes or roles. If a handler retrieves data from a database or cache and serializes it without first validating that the requester is allowed to view each field, the response may expose data belonging to other users or higher-privileged resources. For example, an endpoint like /api/users/{user_id} might load a user record and return it as JSON. If the handler uses a path parameter user_id but does not verify that the caller (via the bearer token) is allowed to access that specific user, any authenticated user with a valid token can enumerate or retrieve other users’ data through ID manipulation. This pattern intersects with BOLA/IDOR, but the presence of a bearer token changes the audit focus: tokens should be treated as authorization context, not mere authentication artifacts.

Another scenario involves token leakage in logs, error messages, or HTTP headers. If an Actix handler serializes request data into responses without filtering sensitive fields, a bearer token that was echoed back or included in debug output can be captured by attackers. Data Exposure checks look for endpoints that return credentials, secrets, or internal objects without redaction or aggregation. They also examine whether CORS configurations expose responses to unauthorized origins, which can amplify the impact by allowing browser-based scripts to read responses that include bearer tokens or user data. MiddleBrick’s unauthenticated scans exercise these routes to identify endpoints where sensitive information is returned without appropriate checks or data minimization.

In combined contexts, a bearer token may be accepted but not properly validated against an authorization model. For instance, an application might verify the token’s signature but skip scope or claim checks, allowing broad access. If the response includes data derived from multiple sources (e.g., combining user profile info with billing details), the aggregation itself can become an exposure vector. middleBrick’s Data Exposure checks map these findings to frameworks such as OWASP API Top 10 and GDPR, emphasizing the need to enforce least privilege and ensure that tokens are tied to precise authorization decisions rather than treated as simple access keys.

Bearer Tokens-Specific Remediation in Actix — concrete code fixes

Remediation focuses on strict validation of bearer tokens at the route or handler level, ensuring that data returned is limited to what the token explicitly permits. Below are concrete Actix examples that demonstrate secure patterns.

1. Validate token ownership before returning user-specific data

Ensure that the requested resource matches the subject of the token. Use extractor patterns to bind authorization context to handlers.

use actix_web::{web, HttpResponse, Responder};
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
struct Claims {
    sub: String,
    scopes: Vec,
}

async fn get_user_profile(
    path: web::Path<String>,
    req: actix_web::HttpRequest,
) -> impl Responder {
    // Extract token from Authorization header
    let auth_header = match req.headers().get("Authorization") {
        Some(h) => h.to_str().unwrap_or(""),
        None => return HttpResponse::Unauthorized().finish(),
    };
    let token = auth_header.strip_prefix("Bearer ").unwrap_or(auth_header);
    if token.is_empty() {
        return HttpResponse::Unauthorized().finish();
    }

    // Decode and validate token (use your own key and validation in production)
    let decoded = match decode::(
        token,
        &DecodingKey::from_secret("secret".as_ref()),
        &Validation::new(Algorithm::HS256),
    ) {
        Ok(d) => d,
        Err(_) => return HttpResponse::Unauthorized().finish(),
    };

    let requested_user_id = path.into_inner();
    // Enforce ownership: only allow access if token subject matches requested ID
    if decoded.claims.sub != requested_user_id {
        return HttpResponse::Forbidden().finish();
    }

    // Fetch and return only data the token permits
    let user_data = serde_json::json!({
        "id": requested_user_id,
        "name": "alice",
        "email": "[email protected]"
    });
    HttpResponse::Ok().json(user_data)
}

2. Scope-based authorization for sensitive endpoints

Use token scopes to gate access to high-sensitivity endpoints and avoid over-fetching data.

async fn admin_endpoint(
    req: actix_web::HttpRequest,
) -> impl Responder {
    let auth_header = match req.headers().get("Authorization") {
        Some(h) => h.to_str().unwrap_or(""),
        None => return HttpResponse::Unauthorized().finish(),
    };
    let token = match auth_header.strip_prefix("Bearer ") {
        Some(t) => t,
        None => return HttpResponse::Unauthorized().finish(),
    };

    let decoded = match decode::(
        token,
        &DecodingKey::from_secret("secret".as_ref()),
        &Validation::new(Algorithm::HS256),
    ) {
        Ok(d) => d,
        Err(_) => return HttpResponse::Unauthorized().finish(),
    };

    if !decoded.claims.scopes.contains(&"admin:read".to_string()) {
        return HttpResponse::Forbidden().json(serde_json::json!({
            "error": "insufficient_scope",
            "message": "Token lacks admin:read scope"
        }));
    }

    // Proceed with admin-only data handling
    HttpResponse::Ok().json(serde_json::json!({
        "system_status": "operational",
        "metrics": { "count": 42 }
    }))
}

3. Avoid token and sensitive data in responses and logs

Do not echo bearer tokens in bodies or headers, and filter sensitive fields before serialization.

async fn safe_user_response(
    req: actix_web::HttpRequest,
) -> impl Responder {
    let auth_header = match req.headers().get("Authorization") {
        Some(h) => h.to_str().unwrap_or(""),
        None => return HttpResponse::Unauthorized().finish(),
    };
    let _token = auth_header.strip_prefix("Bearer ").unwrap_or(auth_header);
    // Do not include the token in the response
    let response = serde_json::json!({
        "user": {
            "id": "u-123",
            "username": "alice"
            // Do not include "token" or raw credentials
        }
    });
    HttpResponse::Ok().json(response)
}

4. Enforce HTTPS and secure header practices

Ensure cookies and tokens are not exposed via insecure channels or verbose errors.

use actix_web::middleware::Logger;
use actix_web::{App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();

    HttpServer::new(|| {
        App::new()
            .wrap(Logger::default())
            // In production, use Secure, HttpOnly flags and consider SameSite
            .service(web::resource("/api/profile").route(web::get().to(get_user_profile)))
    })
    .bind_rustls("0.0.0.0:8443", rustls::ServerConfig::new())? // Configure TLS appropriately
    .expect("Failed to bind")
    .run()
    .await
}

5. Use middleware for centralized authorization checks

Centralize scope and ownership validation to reduce inconsistencies across handlers.

struct AuthValidator;

impl actix_web::dev::Transform<S, ServiceRequest> for AuthValidator
where
    S: actix_web::dev::Service<ServiceRequest, Response = actix_web::dev::ServiceResponse<B>, Error = actix_web::Error>,
    S::Future: 'static,
{
    type Response = actix_web::dev::ServiceResponse<B>;
    type Error = actix_web::Error;
    type InitError = ();
    type Transform = AuthValidatorMiddleware<S>;
    type Future = std::future::Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        std::future::ready(Ok(AuthValidatorMiddleware { service }))
    }
}

struct AuthValidatorMiddleware<S> {
    service: S,
}

impl<S, B> actix_web::dev::Service<ServiceRequest> for AuthValidatorMiddleware<S>
where
    S: actix_web::dev::Service<ServiceRequest, Response = actix_web::dev::ServiceResponse<B>, Error = actix_web::Error>,
    S::Future: 'static,
{
    type Response = actix_web::dev::ServiceResponse<B>;
    type Error = actix_web::Error;
    type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>>>

    fn poll_ready(&self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn call(&self, req: ServiceRequest) -> Self::Future {
        // Perform token validation and ownership checks here
        let authorized = true; // Replace with actual validation
        if !authorized {
            let res = HttpResponse::Forbidden().json(serde_json::json!({
                "error": "forbidden",
                "message": "Token validation failed"
            }));
            return Box::pin(async { Ok(req.into_response(res)) });
        }
        let fut = self.service.call(req);
        Box::pin(async move { fut.await })
    }
}

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

How does middleBrick detect Data Exposure in Actix APIs that use Bearer Tokens?
middleBrick runs unauthenticated black-box checks that exercise endpoints to see whether responses include sensitive data such as user records, internal IDs, or tokens. It looks for missing ownership validation and missing scope checks so that data is only returned when the bearer token’s subject or scopes align with the requested resource.
Can I integrate Bearer Token validation into my CI/CD pipeline using middleBrick?
Yes. With the middleBrick Pro plan, you can use the GitHub Action to add API security checks to your CI/CD pipeline and fail builds if risk scores exceed your threshold. You can also use the CLI (middlebrick scan ) in scripts to enforce bearer token authorization requirements as part of your pipeline.