HIGH bola idorhanamiapi keys

Bola Idor in Hanami with Api Keys

Bola Idor in Hanami with Api Keys — how this combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) occurs when an API exposes an object identifier (such as a numeric ID or UUID) without verifying that the requesting actor is authorized to access that specific object. In Hanami, this typically maps to resource IDs in routes and to explicit checks inside service objects or repositories. When API keys are used for authentication but not coupled with per-request object ownership or tenant checks, BOLA vulnerabilities arise.

Consider a Hanami endpoint designed to retrieve a user profile by ID: /profiles/42. If authentication is implemented only via an API key header (e.g., X-API-Key) and the controller loads the profile by ID without confirming that the profile belongs to the account associated with that key, an attacker can enumerate IDs and read other users’ profiles. The API key proves identity at the application level (a client is allowed to call the API), but it does not enforce object-level permissions, making BOLA possible.

In Hanami, this can happen when authorization logic is implicit or scattered. For example, a controller might call ProfileRepository.new.find(params[:id]) after validating the presence of an API key, but without scoping the query to the authenticated client’s allowed records. If the key is valid but the ID is tampered with, the system may return data that should be restricted. The same risk applies to nested resources: an endpoint like /accounts/123/users/456 might check that the API key belongs to account 123, but then return user 456 without verifying that user 456 is part of account 123.

OpenAPI specifications can inadvertently encourage this if parameters are described as required without clarifying scope. For instance, a path parameter profileId typed as integer suggests it is sufficient to pass an integer, without indicating that the client must also prove ownership. Runtime scanning tools that correlate spec definitions with execution traces can highlight such mismatches by showing that an API key grants access to multiple objects without per-object authorization checks.

Real-world attack patterns include IDOR via predictable numeric IDs and enumeration attacks across UUIDs when authorization is missing. BOLA is not limited to reads: if a Hanami update or delete action uses the same pattern, an attacker can modify or remove objects they do not own. Effective defense requires tying each API key to a scope or tenant and ensuring every data access validates both the key and the target object’s membership in that scope.

Api Keys-Specific Remediation in Hanami — concrete code fixes

Remediation centers on ensuring that every object access is validated against the permissions encoded in the API key. Instead of using the key only for gateway-level authentication, model the key as a scoped credential that maps to a tenant or a set of allowed records. Then enforce scoping in repositories and use explicit checks in controllers.

Example: model your API key as a Hanami entity with associated tenant or account IDs, and use a repository that scopes queries accordingly.

# app/entities/api_key.rb
class ApiKey
  include Hanami::Entity
  attributes :id, :token, :account_id
end

# app/repositories/api_key_repository.rb
class ApiKeyRepository
  def initialize(relation = ApiKeyRepository.relation)
    @relation = relation
  end

  def find_by_token(token)
    @relation.where(token: token).one
  end
end

# app/repositories/profile_repository.rb
class ProfileRepository
  def initialize(relation = ProfileRepository.relation)
    @relation = relation
  end

  # Scoped by account_id to prevent BOLA
  def find_by_id_for_account(id, account_id)
    @relation.where(id: id, account_id: account_id).one
  end
end

# app/controllers/profiles/show.rb
class Profiles::Show
  include Hanami::Action

  def initialize(api_key_repo: ApiKeyRepository.new, profile_repo: ProfileRepository.new)
    @api_key_repo = api_key_repo
    @profile_repo = profile_repo
  end

  def call(params)
    key = @api_key_repo.find_by_token(params[:api_key])
    halt 401, { error: 'unauthorized' }.to_json unless key

    profile = @profile_repo.find_by_id_for_account(params[:id], key.account_id)
    if profile
      { id: profile.id, name: profile.name, account_id: profile.account_id }.to_json
    else
      halt 404, { error: 'not found' }.to_json
    end
  end
end

In this pattern, the API key provides the account_id, and ProfileRepository#find_by_id_for_account ensures that the requested profile belongs to that account. This prevents attackers from iterating IDs across accounts even if they possess valid API keys belonging to other accounts.

For endpoints that accept UUIDs rather than integers, the same principle applies: scope by tenant or owner identifiers. If your API key represents a client with access to multiple organizations, include an organization identifier in the key and validate it on each data fetch.

# Example with UUIDs and explicit ownership check
class Articles::Show
  include Hanami::Action

  def initialize(repo: ArticleRepository.new)
    @repo = repo
  end

  def call(params)
    key = ApiKeyRepository.new.find_by_token(params[:api_key])
    halt 401, { error: 'unauthorized' }.to_json unless key

    article = @repo.find_by_id_and_org(params[:id], key.organization_id)
    # ... render or serialize
  end
end

Where feasible, add instrumentation to detect mismatches between declared scope and runtime access patterns. Although middleBrick does not fix code, its scans can surface inconsistencies between your OpenAPI description and runtime behavior, such as an endpoint that claims to require an API key but does not enforce object-level scoping. Use such findings to refine repository methods and controller actions, ensuring that every object load is bound to the key’s authorization scope.

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

Can API keys alone prevent BOLA in Hanami endpoints?
No. API keys can authenticate a client but do not enforce object-level permissions. You must scope data access to the key’s tenant or ownership context to prevent BOLA.
How does middleBrick relate to BOLA remediation in Hanami?
middleBrick detects and reports BOLA patterns and missing object-level checks, including when API keys are used without proper scoping. It does not fix code; it provides findings and remediation guidance to help you tighten authorization in Hanami.