HIGH bola idorrails

Bola Idor in Rails

How BOLA/IdOR Manifests in Rails

BOLA/IdOR vulnerabilities in Rails applications often stem from ActiveRecord's convenience methods combined with Rails's RESTful routing conventions. The most common pattern involves controller actions that use params[:id] directly to find database records without verifying the current user's authorization.

Consider a typical Rails controller:

class DocumentsController < ApplicationController
def show
@document = Document.find(params[:id])
end
end

This code appears harmless but is vulnerable. An attacker can simply change the ID in the URL to access any document in the database. If user A has document with ID 123 and user B has document with ID 456, user B can access user A's document by visiting /documents/123.

Rails's mass assignment features create another attack vector. When using update_attributes or update with strong parameters, developers often forget to scope the query:

def update
@document = Document.find(params[:id])
@document.update(document_params)
end

The vulnerability becomes more severe when combined with Rails's default parameter handling. If your application uses JSON APIs, an attacker can send additional parameters that get processed by ActiveRecord:

# Vulnerable to IDOR via nested attributes
def update
@user = User.find(params[:id])
@user.update(user_params)
end

ActiveRecord's dynamic finders and the deprecated find_by_id method also contribute to BOLA/IdOR issues when used without proper authorization checks.

Another Rails-specific pattern involves has_many associations. Developers often write code like:

def index
@documents = current_user.documents
end

Which is secure, but then create an edit action that isn't properly scoped:

def edit
@document = Document.find(params[:id]) # Vulnerable!
end

The contrast between the secure index action and the vulnerable edit action makes these vulnerabilities particularly insidious in Rails applications.

Rails-Specific Detection

Detecting BOLA/IdOR vulnerabilities in Rails requires examining both the code structure and runtime behavior. Static analysis can identify risky patterns, but dynamic testing is essential for comprehensive coverage.

Code-level indicators include:

  • Controller actions using Model.find(params[:id]) without authorization checks
  • Missing before_action :authenticate_user! or similar authentication filters
  • Update actions that don't verify record ownership before modification
  • JSON API controllers that accept ID parameters without scoping

middleBrick's Rails-specific scanning analyzes these patterns automatically. When you submit a Rails API endpoint, middleBrick:

  1. Identifies controller actions and their parameter handling
  2. Checks for authentication middleware presence
  3. Analyzes database query patterns for ID-based lookups
  4. Tests authenticated vs unauthenticated access to the same resource

The scanner's active testing phase attempts to access resources using different user contexts. For example, if your API has a user profile endpoint, middleBrick will:

# Test pattern: access /users/1 when authenticated as user 2
curl -H "Authorization: Bearer user2_token" https://api.example.com/users/1

middleBrick also analyzes your OpenAPI/Swagger specification if provided, cross-referencing documented authentication requirements with actual runtime behavior. This catches cases where documentation claims authentication is required but the implementation has gaps.

For Rails applications using Devise or other authentication gems, middleBrick specifically tests the integration between the authentication system and resource access patterns. It verifies that current_user is properly used to scope database queries.

The scanner's 12 parallel security checks include a dedicated BOLA/IdOR assessment that:

  • Tests resource enumeration by incrementing ID parameters
  • Attempts access with different user credentials
  • Checks for information disclosure through error messages
  • Verifies proper authorization headers are enforced

Results are presented with Rails-specific remediation guidance, showing exactly which controller actions need authorization checks and what code changes are required.

Rails-Specific Remediation

Securing Rails applications against BOLA/IdOR requires a combination of architectural patterns and Rails-specific features. The most effective approach is to never use raw ID parameters for record lookup.

Pundit is the Rails community's preferred authorization framework. Here's how to implement it for BOLA/IdOR prevention:

# app/policies/document_policy.rb
class DocumentPolicy < ApplicationPolicy
def show?
record.user == user
end
end

Then in your controller:

class DocumentsController < ApplicationController
before_action :set_document, only: [:show, :edit, :update, :destroy]
before_action :authorize_document, only: [:show, :edit, :update, :destroy]

def show
# Pundit handles authorization
end

private

def set_document
@document = Document.find(params[:id])
end

def authorize_document
authorize @document
end
end

Rails's Concerns feature helps organize authorization logic:

# app/controllers/concerns/authenticated_resource.rb
module AuthenticatedResource
extend ActiveSupport::Concern

included do
before_action :set_and_authorize_resource
end

def set_and_authorize_resource
resource = controller_name.classify.constantize
instance_variable_set("@#{controller_name.singularize}",
resource.find(params[:id]))
authorize instance_variable_get("@#{controller_name.singularize}")
end
end

For JSON APIs, use Pundit's API-friendly helpers:

def show
@document = current_user.documents.find(params[:id])
rescue ActiveRecord::RecordNotFound
render json: { error: 'Not found or unauthorized' }, status: :not_found
end

The key pattern is scoping all queries to the current user. Instead of:

@document = Document.find(params[:id])

Use:

@document = current_user.documents.find(params[:id])

This leverages ActiveRecord's query interface to ensure users can only access their own records. The find method will raise RecordNotFound if the record doesn't exist or doesn't belong to the current user.

For has_many :through associations, be particularly careful:

# Vulnerable
@project = Project.find(params[:id])
@tasks = @project.tasks

Should be:

@project = current_user.projects.find(params[:id])
@tasks = @project.tasks

Rails's default route helpers can also help prevent BOLA/IdOR by using resource-based URLs instead of ID-based ones, though this is more of a convention than a security feature.

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 BOLA/IdOR vulnerabilities in Rails applications?
middleBrick uses dynamic testing to identify BOLA/IdOR issues by attempting to access resources with different user credentials and analyzing the application's response patterns. It examines controller actions for ID-based lookups without proper authorization checks, tests authenticated vs unauthenticated access to the same resources, and verifies that authentication middleware is properly integrated with resource access patterns. The scanner also analyzes your OpenAPI/Swagger specification to cross-reference documented authentication requirements with actual runtime behavior.
What's the difference between BOLA and IdOR in Rails applications?
BOLA (Broken Object Level Authorization) and IdOR (Insecure Direct Object References) are essentially the same vulnerability in Rails contexts. Both refer to the failure to properly verify that a user is authorized to access a specific resource. The terms are used interchangeably in the Rails community. The core issue is that Rails applications often use params[:id] directly in ActiveRecord queries without checking whether the current user owns or has permission to access that specific record. This allows attackers to manipulate ID parameters to access unauthorized resources.