HIGH bola idorhanamicockroachdb

Bola Idor in Hanami with Cockroachdb

Bola Idor in Hanami with Cockroachdb — how this specific combination creates or exposes the vulnerability

BOLA (Broken Level of Authorization) / IDOR occurs when an API exposes internal object identifiers (IDs) and does not enforce that the requesting user is authorized to access the specific resource. In Hanami, this often maps to model instances fetched via public-facing keys (e.g., params[:id]) without verifying ownership or tenant context. When you use Cockroachdb as the backend, the risk is shaped by how IDs are generated, how queries are built, and how data is partitioned.

Hanami encourages explicit, intention-revealing routes and uses value objects for IDs (e.g., AccountID). If these IDs are predictable (e.g., integers or UUIDs derived from non-tenant context), and the authorization check is omitted or shallow, an attacker can iterate through IDs and access other users’ data. Cockroachdb’s distributed SQL nature does not prevent BOLA, but certain patterns amplify exposure:

  • Multi-tenant data isolation is implemented at the application level rather than the database level. If queries do not include tenant context (e.g., account_id), Cockroachdb will return rows it can see, and Hanami must filter them.
  • Using Cockroachdb-generated UUIDs (with gen_random_uuid() or via ORM defaults) can produce opaque IDs; if these IDs are exposed in URLs without verifying the caller’s relationship to the record, enumeration is straightforward.
  • Complex joins or secondary indexes in Cockroachdb can inadvertently expose related records if queries are not constrained by tenant or ownership predicates in Hanami mappers.

A concrete scenario: a Hanami endpoint GET /api/v1/invoices/:id uses InvoiceRepository.new.find(params[:id]). If the repository does not scope by account_id and the invoice IDs are sequential integers or guessable UUIDs, an attacker can request invoices belonging to other accounts. Cockroachdb will serve the row if it exists; Hanami must enforce that the authenticated actor owns or is permitted to view that invoice. Without this check, the combination of a predictable ID space and a permissive query surface creates BOLA/IDOR.

Cockroachdb-Specific Remediation in Hanami — concrete code fixes

Remediation centers on scoping every data access with tenant or ownership context and avoiding reliance on ID obscurity. Below are concrete Hanami patterns and Cockroachdb-aware code examples.

1. Scope queries by tenant/actor

Ensure every repository query includes the actor’s identifier. If you use an Account aggregate, embed account_id in the domain model and enforce it at the mapper layer.

# app/repositories/invoice_repository.rb
class InvoiceRepository
  def initialize(account_repo: AccountRepository.new)
    @account_repo = account_repo
  end

  def for_account(account_id)
    invoices = DB[:invoices].where(account_id: account_id).to_a
    invoices.map { |attrs| Invoice.new(attrs) }
  end

  def find_by_id(account_id, invoice_id)
    row = DB[:invoices].where(id: invoice_id, account_id: account_id).first
    row ? Invoice.new(row) : nil
  end
end

In your Hanami use case, call invoice_repo.find_by_id(current_account.id, params[:id]). This ensures Cockroachdb only returns rows where both ID and tenant match.

2. Use opaque, unguessable IDs with ownership binding

Prefer UUIDs generated by the application (not solely by Cockroachdb) and bind them to an account at creation time. This prevents ID enumeration across tenants.

# app/entities/invoice.rb
class Invoice
  include Hanami::Entity
  attribute :id, Types::Strict::String
  attribute :account_id, Types::Strict::String
  # other attributes...
end

# app/repositories/invoice_repository.rb
class InvoiceRepository
  def create(attributes)
    id = SecureRandom.uuid
    DB[:invoices].insert(id: id, account_id: attributes[:account_id], amount: attributes[:amount])
    find_by_id(attributes[:account_id], id)
  end
end

When exposing IDs in URLs, use these UUIDs; the authorization check in find_by_id will still validate account_id.

3. Enforce ownership in the domain service, not just the repository

Repositories can be bypassed if multiple entry points exist. Implement a domain service that validates ownership before performing sensitive operations.

# app/services/invoice_access_service.rb
class InvoiceAccessService
  def initialize(invoice_repo: InvoiceRepository.new, auth: CurrentAccount)
    @invoice_repo = invoice_repo
    @auth = auth
  end

  def view_invoice(invoice_id)
    invoice = invoice_repo.find_by_id(@auth.account.id, invoice_id)
    raise Hanami::Action::UnauthorizedError unless invoice
    invoice
  end
end

Use this service in your action: InvoiceAccessService.new(view_invoice: params[:id]).view_invoice. This guarantees that even if a developer forgets to scope a query, the service layer will enforce tenant alignment.

4. Validate input to avoid Cockroachdb-specific edge cases

Cockroachdb supports complex SQL features; ensure your Hanami queries do not inadvertently expose data through joins or CTEs. Always parameterize inputs and avoid interpolating IDs into raw SQL fragments.

# Safe: parameterized query
DB[:invoices].where(Sequel.lit('id = ?', invoice_id)).limit(1).first

# Avoid: string interpolation that may bypass scoping
# DB["SELECT * FROM invoices WHERE id = #{invoice_id}"].first

Also, review secondary indexes and computed columns in Cockroachdb to ensure they do not expose relationships that should remain hidden across tenants.

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

Does using Cockroachdb change the way I should handle IDs in Hanami to prevent IDOR?
Yes. Prefer application-generated opaque UUIDs, bind them to tenant/account at creation, and always scope queries by account_id. Avoid relying on sequential integers or Cockroachdb-only generation without ownership checks.
Is it enough to just add a where(account_id: ...) clause in my Hanami repositories?
It is necessary but not sufficient. Ensure every entry point that loads a record by ID enforces ownership, including services, API actions, and background jobs. Consider a domain service that centralizes authorization to prevent accidental bypasses.