HIGH insecure direct object referenceactix

Insecure Direct Object Reference in Actix

How Insecure Direct Object Reference Manifests in Actix

Insecure Direct Object Reference (IDOR) in Actix applications typically occurs when route parameters are used directly to access database records without proper authorization checks. This vulnerability allows attackers to manipulate identifiers in API requests to access resources they shouldn't have permission to view or modify.

A common Actix pattern that creates IDOR vulnerabilities looks like this:

async fn get_user_profile(info: web::Path<(String, String)>, db: web::Data) -> impl Responder {
    let (user_id, profile_id) = info.into_inner();
    
    // Direct database access using user-provided ID
    let result = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
        .bind(user_id)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(user) => HttpResponse::Ok().json(user),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

This code is vulnerable because it trusts the user_id parameter from the URL without verifying that the authenticated user has permission to access that specific user's data. An attacker could simply change the user_id in the request to access any user's profile.

Another Actix-specific IDOR pattern occurs with query parameters:

async fn get_document(info: web::Query, db: web::Data) -> impl Responder {
    let doc_id = info.doc_id;
    
    // No authorization check before accessing document
    let result = sqlx::query_as::<_, Document>("SELECT * FROM documents WHERE id = $1")
        .bind(doc_id)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(doc) => HttpResponse::Ok().json(doc),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

Actix's strong typing and async/await patterns can actually make IDOR more dangerous when combined with improper authorization. The clean, straightforward syntax can create a false sense of security, leading developers to overlook authorization checks.

Path-based IDOR is particularly common in Actix applications with hierarchical resource structures:

async fn get_team_project(info: web::Path<(String, String)>, db: web::Data) -> impl Responder {
    let (team_id, project_id) = info.into_inner();
    
    // Direct access using both IDs without authorization
    let result = sqlx::query_as::<_, Project>("SELECT * FROM projects WHERE team_id = $1 AND id = $2")
        .bind(team_id)
        .bind(project_id)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(project) => HttpResponse::Ok().json(project),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

The vulnerability here is that while the query filters by both team_id and project_id, there's no check to ensure the authenticated user belongs to that team or has access to that project.

Actix-Specific Detection

Detecting IDOR vulnerabilities in Actix applications requires both static analysis and dynamic testing. For static analysis, look for patterns where route parameters are directly used in database queries without authorization checks.

middleBrick's API security scanner can detect IDOR vulnerabilities in Actix applications by analyzing the unauthenticated attack surface. The scanner tests for IDOR by attempting to access resources using manipulated identifiers and checking if authorization controls are properly enforced.

Here's how you can use middleBrick to scan an Actix API endpoint:

# Install middleBrick CLI
npm install -g middlebrick

# Scan an Actix API endpoint
middlebrick scan https://api.example.com/users/{user_id}/profile

The scanner will test for IDOR by attempting to access different user IDs and checking if the application properly restricts access. It looks for responses that indicate whether a resource exists without proper authorization.

For manual testing of Actix applications, you can use tools like curl or Postman to test IDOR vulnerabilities:

# Test if you can access another user's profile
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.example.com/users/999/profile

# Test if you can access documents by ID
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.example.com/documents/9999

Look for responses that return 200 OK with data for resources you shouldn't have access to, or 404 Not Found that reveals whether a resource exists (information disclosure).

middleBrick's scanning includes specific checks for Actix patterns, such as:

  • Path parameter injection testing
  • Query parameter manipulation
  • Header-based IDOR attempts
  • Cross-user resource access attempts
  • Enumeration of valid resource IDs

The scanner provides a security score and detailed findings, helping you identify which endpoints are vulnerable to IDOR attacks.

Actix-Specific Remediation

Remediating IDOR vulnerabilities in Actix applications requires implementing proper authorization checks before accessing resources. The most effective approach is to use Actix's middleware and extractors to centralize authorization logic.

Here's a secure pattern using Actix middleware for authorization:

use actix_web::{dev::ServiceRequest, dev::ServiceResponse, HttpMessage, Error};
use actix_web::middleware::Middleware;
use actix_web::web::Data;
use sqlx::Pool;

struct AuthorizationMiddleware;

impl Middleware for AuthorizationMiddleware {
    async fn call(&self, req: ServiceRequest, srv: &S) -> Result
    where
        S: actix_web::dev::Service,
    {
        // Extract user ID from token
        let user_id = match extract_user_id_from_token(req.headers()) {
            Some(id) => id,
            None => {
                return Ok(req.into_response(
                    HttpResponse::Unauthorized().finish()
                ));
            }
        };

        // Store user ID in request extension for later use
        req.extensions_mut().insert::(UserId(user_id));
        
        srv.call(req).await
    }
}

#[derive(Clone)]
struct UserId(String);

async fn get_user_profile(
    info: web::Path<(String, String)>, 
    db: web::Data,
    user_id: web::ReqData
) -> impl Responder {
    let (requested_user_id, profile_id) = info.into_inner();
    
    // Check if user is accessing their own profile or has admin rights
    if requested_user_id != user_id.0 && !is_admin(&db, &user_id.0).await? {
        return HttpResponse::Forbidden().finish();
    }
    
    // Now it's safe to access the user's profile
    let result = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
        .bind(requested_user_id)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(user) => HttpResponse::Ok().json(user),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

This pattern ensures that every request goes through authorization middleware before reaching the handler, preventing IDOR vulnerabilities.

For resource-specific authorization, use Actix's extractors to validate access rights:

async fn get_team_project(
    info: web::Path<(String, String)>, 
    db: web::Data,
    user_id: web::ReqData
) -> impl Responder {
    let (team_id, project_id) = info.into_inner();
    
    // Check if user belongs to team and has project access
    if !has_team_access(&db, &user_id.0, &team_id).await? {
        return HttpResponse::Forbidden().finish();
    }
    
    // Check if user has access to specific project
    if !has_project_access(&db, &user_id.0, &project_id).await? {
        return HttpResponse::Forbidden().finish();
    }
    
    // Safe to access project data
    let result = sqlx::query_as::<_, Project>("SELECT * FROM projects WHERE team_id = $1 AND id = $2")
        .bind(team_id)
        .bind(project_id)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(project) => HttpResponse::Ok().json(project),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

Another effective pattern is using Actix's request extension to store user context:

use actix_web::FromRequest;

struct AuthenticatedUser(String);

impl FromRequest for AuthenticatedUser {
    type Error = actix_web::Error;
    type Future = futures::future::Ready>;
    type Config = ();

    fn from_request(req: &HttpRequest, payload: &mut actix_web::dev::Payload) -> Self::Future {
        // Extract and validate user from token
        let user_id = extract_user_id_from_token(req.headers());
        
        if let Some(id) = user_id {
            futures::future::ready(Ok(AuthenticatedUser(id)))
        } else {
            futures::future::ready(Err(actix_web::error::ErrorUnauthorized("Unauthorized")))
        }
    }
}

async fn get_user_data(
    user_id: web::Path,
    auth_user: AuthenticatedUser,
    db: web::Data
) -> impl Responder {
    // Check if authenticated user can access requested user data
    if user_id.0 != auth_user.0 && !is_admin(&db, &auth_user.0).await? {
        return HttpResponse::Forbidden().finish();
    }
    
    // Safe to proceed with data access
    let result = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
        .bind(user_id.0)
        .fetch_one(&db)
        .await;
    
    match result {
        Ok(user) => HttpResponse::Ok().json(user),
        Err(_) => HttpResponse::NotFound().finish(),
    }
}

These patterns ensure that IDOR vulnerabilities are prevented by validating user permissions before any database access occurs, leveraging Actix's type system and middleware architecture for secure API design.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

How does middleBrick detect IDOR vulnerabilities in Actix applications?
middleBrick performs black-box scanning by testing API endpoints with manipulated identifiers. It attempts to access resources using different IDs and checks if authorization controls are properly enforced. The scanner looks for responses that indicate whether a resource exists without proper authorization, testing path parameters, query parameters, and header-based IDOR attempts. It provides a security score and detailed findings specific to IDOR vulnerabilities.
Can I integrate middleBrick scanning into my Actix CI/CD pipeline?
Yes, you can use the middleBrick GitHub Action to add API security scanning to your CI/CD pipeline. Add it to your workflow to scan staging APIs before deployment, with configurable thresholds to fail builds if security scores drop below your defined limits. This ensures IDOR and other vulnerabilities are caught early in the development process.