HIGH integrity failuresactix

Integrity Failures in Actix

How Integrity Failures Manifests in Actix

Integrity failures in Actix applications typically occur when the framework's powerful routing and extraction mechanisms are combined with insufficient authorization checks. Actix's path parameter extraction and JSON deserialization features, while convenient, can create security gaps if developers assume that matching a route automatically authorizes access to the resource.

A common pattern involves Actix's Path extractor combined with database operations. Consider an endpoint that retrieves user data by ID:

use actix_web::{get, web, HttpResponse, Responder};
use serde::Deserialize;

#[derive(Deserialize)]
struct UserDataParams {
    user_id: i32,
}

#[get("/users/{user_id}")]
async fn get_user(params: web::Path<UserDataParams>, db: web::Data<PgPool>) -> impl Responder {
    let user = sqlx::query_as("SELECT * FROM users WHERE id = $1")
        .bind(params.user_id)
        .fetch_one(&db)
        .await?;
    
    HttpResponse::Ok().json(user)
}

This endpoint is vulnerable to IDOR (Insecure Direct Object Reference) attacks. Any authenticated user can modify the user_id parameter to access other users' data. Actix's path extraction makes it trivial to manipulate these values, and without proper authorization checks, the integrity of user data is compromised.

Another manifestation occurs with Actix's JSON deserialization. The framework's Json extractor automatically parses request bodies into structs:

use actix_web::{post, web, HttpResponse, Responder};
use serde::Deserialize;

#[derive(Deserialize)]
struct UpdateUserRequest {
    email: String,
    phone: String,
}

#[post("/users/{user_id}/update")]
async fn update_user(
    params: web::Path<UserIdParams>,
    body: web::Json<UpdateUserRequest>,
    db: web::Data<PgPool>,
) -> impl Responder {
    sqlx::query("UPDATE users SET email = $1, phone = $2 WHERE id = $3")
        .bind(body.email.clone())
        .bind(body.phone.clone())
        .bind(params.user_id)
        .execute(&db)
        .await?;
    
    HttpResponse::Ok().finish()
}

This endpoint suffers from both BOLA (Broken Object Level Authorization) and BFLA (Broken Function Level Authorization) vulnerabilities. An attacker can update any user's profile by simply changing the user_id in the URL, regardless of whether they own that account or have permission to perform the update.

Actix's middleware system can also contribute to integrity failures when authentication checks are incomplete. A common mistake is implementing authentication middleware that only verifies the presence of a token, not whether the token grants access to the specific resource being requested:

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

async fn auth_middleware(
    req: actix_web::dev::ServiceRequest,
    srv: &mut actix_web::dev::Service<actix_web::dev::ServiceRequest, actix_web::dev::ServiceResponse>,
) -> actix_web::Result<actix_web::dev::ServiceResponse> {
    // Only checks for token presence, not resource ownership
    if let Some(auth) = req.headers().get("Authorization") {
        return srv.call(req);
    }
    
    Ok(req.into_response(
        HttpResponse::Unauthorized().finish().into_body()
    ))
}

This middleware would allow any authenticated user to access any resource, completely failing to enforce data integrity boundaries.

Actix-Specific Detection

Detecting integrity failures in Actix applications requires examining both the routing patterns and the authorization logic that connects requests to data access. The framework's declarative routing makes it straightforward to identify endpoints that accept path parameters or JSON bodies without corresponding authorization checks.

Static analysis of Actix route definitions can reveal potential vulnerabilities. Look for patterns where web::Path or web::Json extractors are used without subsequent authorization checks:

use actix_web::{get, post, web, Responder};

// Vulnerable pattern - no authorization check
#[get("/accounts/{account_id}")]
async fn get_account(params: web::Path<AccountId>) -> impl Responder {
    // Direct database access using path parameter
    Account::find_by_id(params.account_id)
}

// Secure pattern - includes authorization
#[get("/accounts/{account_id}")]
async fn get_account(
    params: web::Path<AccountId>,
    auth: actix_web::middleware::ExtractJwt,
    db: web::Data<DbPool>,
) -> impl Responder {
    // Verify user owns this account
    if !auth.user().owns_account(params.account_id) {
        return HttpResponse::Forbidden().finish();
    }
    
    Account::find_by_id(params.account_id)
}

Dynamic scanning with middleBrick can identify these vulnerabilities by actively testing the unauthenticated attack surface. The scanner examines Actix endpoints for BOLA/IDOR vulnerabilities by systematically modifying path parameters and JSON payloads to access resources that should be protected. For example, it would test whether changing user_id in /users/{user_id} endpoints returns different users' data.

middleBrick's OpenAPI analysis is particularly effective for Actix applications since the framework's route definitions map cleanly to OpenAPI specifications. The scanner cross-references the spec's parameter definitions with actual runtime behavior, identifying endpoints where parameters are used in database queries without corresponding security constraints.

Property authorization failures in Actix often involve partial object disclosure. The framework's serialization features can inadvertently expose sensitive fields:

#[derive(Serialize)]
struct User {
    id: i32,
    email: String,
    ssn: String,  // Should not be exposed to all users
    balance: f64, // Financial data requiring authorization
}

#[get("/users/{id}")]
async fn get_user(params: web::Path<i32>) -> impl Responder {
    let user = User::find_by_id(params.id);
    HttpResponse::Ok().json(user)  // Exposes all fields
}

middleBrick detects these property authorization issues by analyzing the data structures returned by Actix endpoints and comparing them against expected access patterns for different user roles.

Actix-Specific Remediation

Remediating integrity failures in Actix applications requires implementing proper authorization checks that verify both user identity and resource ownership. Actix's middleware and extractor systems provide excellent foundations for building secure authorization layers.

The most effective approach is creating a custom authorization extractor that validates resource access before the handler executes:

use actix_web::{get, post, web, Responder, HttpResponse, http::header};
use actix_web::dev::ServiceRequest;

// Custom extractor for authorized access
pub struct AuthorizedResource<T> {
    pub resource: T,
    pub user_id: i32,
}

impl<T> actix_web::FromRequest for AuthorizedResource<T>
where
    T: actix_web::FromRequest,
{
    type Config = T::Config;
    type Error = actix_web::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;

    fn from_request(
        req: &ServiceRequest,
        payload: &mut actix_web::dev::Payload,
    ) -> Self::Future {
        let fut = T::from_request(req, payload);
        
        Box::pin(async move {
            let resource = fut.await?;
            
            // Extract user ID from authentication
            let user_id = req
                .headers()
                .get("X-User-Id")
                .and_then(|h| h.to_str().ok())
                .and_then(|s| s.parse().ok())
                .ok_or_else(|| HttpResponse::Unauthorized().finish())?;
            
            // Verify resource ownership
            if !verify_ownership(&resource, user_id).await? {
                return Err(HttpResponse::Forbidden().finish().into());
            }
            
            Ok(AuthorizedResource { resource, user_id })
        })
    }
}

// Usage in handlers
#[get("/users/{user_id}")]
async fn get_user(
    params: web::Path<i32>,
    auth: AuthorizedResource<i32>,
) -> impl Responder {
    // auth.resource == params.user_id and ownership verified
    let user = User::find_by_id(auth.resource).await?;
    HttpResponse::Ok().json(user)
}

For property-level authorization, Actix's serialization features can be leveraged to control field exposure based on user roles:

use actix_web::{get, Responder};
use serde::{Serialize, Serializer};

#[derive(Serialize)]
struct User {
    id: i32,
    email: String,
    #[serde(serialize_with = "serialize_sensitive_fields")]
    sensitive_data: SensitiveData,
}

#[derive(Serialize)]
struct SensitiveData {
    ssn: String,
    balance: f64,
}

fn serialize_sensitive_fields<S>(
    data: &SensitiveData,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    // Conditionally serialize based on user role
    let req = actix_web::HttpRequest::current();
    let user_role = req.headers().get("X-User-Role")?.to_str()?;
    
    if user_role == "admin" {
        SensitiveData { ssn: data.ssn.clone(), balance: data.balance }.serialize(serializer)
    } else {
        // Return empty or redacted data
        SensitiveData { ssn: "REDACTED".to_string(), balance: 0.0 }.serialize(serializer)
    }
}

Actix's middleware system is ideal for implementing cross-cutting authorization policies:

use actix_web::{middleware, web, App, HttpServer, HttpResponse};

struct AuthorizationMiddleware;

impl middleware::Middleware for AuthorizationMiddleware {
    fn start(&self, req: &ServiceRequest) -> actix_web::Result<middleware::Started> {
        // Check if user is authenticated
        if let Some(auth) = req.headers().get("Authorization") {
            // Extract user ID and roles from token
            let user_info = decode_token(auth.to_str()?)?;
            
            // Store user info for later use
            req.extensions_mut().insert(user_info);
            
            Ok(middleware::Started::Done)
        } else {
            Ok(middleware::Started::Done) // Continue without auth
        }
    }

    fn finish(&self, req: &ServiceRequest, resp: &ServiceResponse) -> actix_web::Result<()> {
        // Log or audit authorization decisions
        Ok(())
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .wrap(AuthorizationMiddleware)
            .service(get_user)
            .service(update_user)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Database-level authorization using row-level security (RLS) provides an additional defense layer that complements Actix's application-level checks:

// PostgreSQL RLS policy
CREATE POLICY user_access ON users
    FOR SELECT USING (id = current_setting('app.current_user_id')::int);

// Actix integration
async fn get_user_with_rls(
    params: web::Path<i32>,
    db: web::Data<PgPool>,
) -> impl Responder {
    // Set RLS context
    sqlx::query("SET app.current_user_id = $1")
        .bind(params.user_id)
        .execute(&db)
        .await?;
    
    // RLS automatically filters results
    let user = sqlx::query_as("SELECT * FROM users WHERE id = $1")
        .bind(params.user_id)
        .fetch_one(&db)
        .await?;
    
    HttpResponse::Ok().json(user)
}

Frequently Asked Questions

How does middleBrick detect integrity failures in Actix applications?
middleBrick scans Actix endpoints by systematically testing path parameters and JSON payloads to identify BOLA/IDOR vulnerabilities. It examines OpenAPI specifications generated from Actix route definitions and cross-references them with runtime behavior. The scanner actively modifies parameters like user IDs in URLs to determine if endpoints return unauthorized data, and analyzes data structures for property authorization issues where sensitive fields are exposed without proper access controls.
What makes Actix particularly vulnerable to integrity failures?
Actix's powerful extraction mechanisms and declarative routing make it easy to write endpoints that automatically parse path parameters and JSON bodies without requiring explicit authorization checks. The framework's convenience features like web::Path and web::Json extractors can create a false sense of security, leading developers to assume that matching a route implies authorization. Additionally, Actix's serialization features can inadvertently expose sensitive data fields if not properly controlled with role-based access controls.