HIGH bola idorhanami

Bola Idor in Hanami

How Bola Idor Manifests in Hanami

BOLA (Broken Object Level Authorization) and IDOR (Insecure Direct Object Reference) vulnerabilities in Hanami applications typically arise from improper authorization checks when handling resource identifiers in URLs or request parameters. These vulnerabilities allow authenticated users to access or manipulate objects they don't own by simply changing identifiers in requests.

In Hanami, these vulnerabilities often manifest in controller actions that accept IDs from parameters without verifying resource ownership. For example, a typical vulnerable pattern looks like this:

module Web::Controllers::Posts
  class Show
    include Web::Action

    def call(params)
      @post = PostRepository.new.find(params[:id])
      # No authorization check
    end
  end
end

The repository pattern in Hanami, while elegant, can hide authorization logic. Developers often assume that finding a record by ID is sufficient, but this creates a critical security gap. An attacker who knows another user's post ID can simply modify the URL to access unauthorized content.

Another common manifestation occurs in update/delete operations:

module Web::Controllers::Posts
  class Update
    include Web::Action

    def call(params)
      @post = PostRepository.new.find(params[:id])
      PostRepository.new.update(@post.id, params[:post])
      # No check that current_user owns @post
    end
  end
end

Hanami's slice architecture can exacerbate these issues when business logic is scattered across slices. A Posts slice might handle CRUD operations without awareness of user context, while the Accounts slice manages authentication separately. This separation can lead to authorization logic being forgotten or bypassed.

RESTful routing in Hanami applications often creates predictable URL patterns (e.g., /posts/:id, /users/:id), making it easier for attackers to enumerate and test for BOLA/IDOR vulnerabilities. The framework's convention-over-configuration approach means developers might not consider security implications when following standard patterns.

Hanami-Specific Detection

Detecting BOLA/IDOR vulnerabilities in Hanami applications requires examining controller actions for proper authorization patterns. The key indicators include:

  • Repository calls using params[:id] without subsequent authorization checks
  • Missing before_actions that verify resource ownership
  • Actions that accept user IDs or resource IDs without validating the current user's permissions

middleBrick's scanner can detect these patterns through black-box testing of your Hanami API endpoints. The scanner automatically tests for BOLA vulnerabilities by:

  1. Identifying endpoints that accept resource identifiers
  2. Modifying those identifiers to access other users' data
  3. Analyzing responses to determine if authorization is properly enforced

For Hanami applications, middleBrick specifically looks for:

# Scan your Hanami API endpoint
middlebrick scan https://api.yourapp.com

The scanner tests common Hanami patterns like:

  • /api/v1/posts/:id - testing if users can access other users' posts
  • /api/v1/users/:id - checking if user profile data is properly protected
  • /api/v1/comments/:id - verifying comment ownership enforcement

middleBrick's OpenAPI analysis also examines your Hanami application's spec files to identify parameter definitions that could be vulnerable to BOLA attacks, then correlates these with runtime findings.

Manual code review should focus on:

# Look for patterns like this
post = PostRepository.new.find(params[:id])
# Is there a check like this?
raise Unauthorized unless post.user_id == current_user.id?

Hanami's dependency injection can sometimes obscure authorization logic. When repositories are injected without proper scoping, they may return records regardless of the current user's permissions.

Hanami-Specific Remediation

Remediating BOLA/IDOR vulnerabilities in Hanami requires implementing proper authorization checks at the repository or controller level. The most effective approach uses Hanami's slice architecture to create scoped repositories.

First, create a scoped repository pattern:

# apps/web/lib/web/repositories/scoped_post_repository.rb
module Web::Repositories
  class ScopedPostRepository
    def initialize(current_user)
      @current_user = current_user
      @repository = PostRepository.new
    end

    def find(id)
      post = @repository.find(id)
      raise Unauthorized unless post.user_id == @current_user.id
      post
    end

    def all
      @repository.where(user_id: @current_user.id)
    end

    def create(data)
      @repository.create(data.merge(user_id: @current_user.id))
    end

    def update(id, data)
      post = find(id)
      @repository.update(post.id, data)
    end

    def delete(id)
      post = find(id)
      @repository.delete(post.id)
    end
  end
end

Then use this in your controller:

module Web::Controllers::Posts
  class Show
    include Web::Action

    def initialize(scoped_post_repository: ScopedPostRepository.new(current_user))
      @scoped_post_repository = scoped_post_repository
    end

    def call(params)
      @post = @scoped_post_repository.find(params[:id])
    end
  end
end

Alternatively, use Hanami's policies for authorization:

# apps/web/lib/web/policies/post_policy.rb
module Web::Policies
  class PostPolicy
    def initialize(current_user, post)
      @current_user = current_user
      @post = post
    end

    def can_view?
      @post.user_id == @current_user.id
    end

    def can_edit?
      can_view?
    end

    def can_delete?
      can_view?
    end
  end
end

Integrate policies into controllers:

module Web::Controllers::Posts
  class Show
    include Web::Action

    def call(params)
      @post = PostRepository.new.find(params[:id])
      policy = PostPolicy.new(current_user, @post)
      raise Unauthorized unless policy.can_view?
    end
  end
end

For Hanami applications using JWT authentication, ensure the current_user is properly injected:

# apps/web/lib/web/middleware/auth_middleware.rb
module Web::Middleware
  class AuthMiddleware
    def initialize(app, options = {})
      @app = app
    end

    def call(env)
      request = Rack::Request.new(env)
      token = request.get_header('HTTP_AUTHORIZATION')&.split&.last
      
      if token
        payload = JwtService.decode(token)
        env['hanami.current_user'] = UserRepository.new.find(payload['user_id'])
      end

      @app.call(env)
    end
  end
end

Finally, implement comprehensive testing:

# spec/web/controllers/posts_controller_spec.rb
RSpec.describe Web::Controllers::Posts::Show do
  let(:post) { PostRepository.new.create(user_id: other_user.id, title: 'Test') }
  
  it 'prevents access to other users posts' do
    response = subject.call(id: post.id)
    expect(response.status).to eq(403)
  end
end

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 Hanami applications?
middleBrick uses black-box scanning to test your Hanami API endpoints by modifying resource identifiers in requests and analyzing responses. The scanner identifies endpoints that accept IDs, systematically tests access to other users' resources, and checks if authorization is properly enforced. It also analyzes your OpenAPI spec to identify parameter definitions that could be vulnerable, then correlates these findings with runtime testing results.
What's the difference between BOLA and IDOR in Hanami applications?
In Hanami applications, BOLA (Broken Object Level Authorization) is the broader category of authorization failures at the object level, while IDOR (Insecure Direct Object Reference) is a specific implementation flaw where direct object references (like database IDs) are exposed in URLs without proper authorization checks. All IDOR vulnerabilities are BOLA, but BOLA also includes issues like missing authorization checks in business logic, improper role-based access control, and other object-level authorization failures beyond just direct ID references.