HIGH broken access controlhanamifirestore

Broken Access Control in Hanami with Firestore

Broken Access Control in Hanami with Firestore — how this specific combination creates or exposes the vulnerability

Broken Access Control occurs when Hanami applications fail to enforce proper authorization checks between users and Firestore resources. Because Hanami is a Ruby web framework with an object-oriented architecture, developers often map Firestore documents directly to domain models and assume visibility in one layer implies visibility across the stack. This assumption is dangerous when Firestore security rules are not aligned with Hanami’s authorization logic.

In a typical Hanami + Firestore setup, the client (web or mobile) may call an endpoint such as /api/v1/notes/:id. Hanami loads the requested record from Firestore using a document ID that may be user-provided. If the application verifies only that a user is authenticated and does not confirm that the requested document belongs to the user’s tenant or scope, an authenticated user can change the document ID to access another user’s data. Because Firestore rules may be misconfigured to allow broad read access in development or may rely only on simplistic uid-based rules, the vulnerability becomes exploitable in production when rules are more permissive than intended.

Firestore-specific weaknesses that amplify Broken Access Control include:

  • Rule scope gaps: Rules that allow read or write based only on authentication (request.auth != null) without validating tenant IDs or ownership fields.
  • Overly permissive wildcard rules: Rules using allow read, write: if true; or broad path patterns during prototyping that are never tightened before deployment.
  • Insecure document ID handling: Using predictable or sequential IDs that make enumeration trivial, enabling attackers to iterate through valid document references.

Because middleBrick scans the unauthenticated attack surface, it can detect endpoints where Firestore rules permit broader access than Hanami’s business logic enforces. Findings typically highlight mismatches between Firestore rule conditions and Hanami’s authorization checks, such as missing ownership validation or missing resource-level constraints. Attack patterns like BOLA (Broken Object Level Authorization) often map to this issue, where an attacker manipulates identifiers to gain unauthorized access across user boundaries.

Firestore-Specific Remediation in Hanami — concrete code fixes

To remediate Broken Access Control, align Firestore security rules with Hanami’s authorization model and enforce ownership checks on every request. Below are concrete, realistic examples for Hanami apps using Firestore via the official Google Cloud client library.

1. Firestore security rules (Firestore in Native mode)

Define rules that scope reads and writes to the authenticated user’s data. Use request.auth.uid and a structured path that includes a tenant or user segment.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow users to read/write only their own notes under their user document
    match /users/{userId}/notes/{noteId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    // Example: scoped collection for team resources with explicit role checks
    match /teams/{teamId}/members/{memberId} {
      allow read: if request.auth != null && isTeamMember(request.auth.uid, teamId);
      allow write: if request.auth != null && request.auth.uid == memberId;
    }
    // Helper to check membership (simplified)
    function isTeamMember(uid, teamId) {
      return exists(/databases/$(database)/documents/teams/$(teamId)/members/$(uid));
    }
  }
}

2. Hanami endpoint with explicit ownership check

In your Hanami endpoint, resolve the current user’s ID from the session or token, then use it to scope the Firestore query. Avoid using raw IDs from params directly.

# app/actions/api/notes/show.rb
module Api::Notes
  class Show
    include Hanami::Action

    def initialize(notes_repo: Repositories::Notes.new, auth: Auth.current_user_method)
      @notes_repo = notes_repo
      @auth = auth
    end

    def call(params)
      user = @auth.call(params)
      return halt(401, { error: 'unauthorized' }.to_json) unless user

      note = @notes_repo.find_by_id_and_user(params[:id], user.id)
      if note
        Response::JSON.new(note, status: 200)
      else
        halt(404, { error: 'not_found' }.to_json)
      end
    end
  end

# app/repositories/notes.rb
module Repositories
  class Notes
    def initialize(gateway: Gateways::Firestore.new)
      @gateway = gateway
    end

    def find_by_id_and_user(id, user_id)
      doc = @gateway.collection('users').doc(user_id).collection('notes').doc(id).get
      doc.exists? ? doc.data.merge('id' => doc.id) : nil
    end
  end

  module Gateways
    class Firestore
      def initialize(project_id: ENV['FIRESTORE_PROJECT_ID'])
        @client = Google::Cloud.firestore project: project_id
      end

      def collection(path)
        @client.collection(path)
      end
    end
  end
end

3. Defense-in-depth practices

  • Validate and normalize IDs in Hanami to avoid enumeration; prefer UUIDs over sequential integers.
  • Use Firestore get with explicit path composition that includes the user ID, rather than querying by arbitrary client-supplied references.
  • Log access denials and monitor rule evaluation outcomes in Cloud Logging to detect attempted bypasses.

By combining precise Firestore rules that enforce ownership at the database level with Hanami’s own authorization checks, you reduce the attack surface for Broken Access Control. middleBrick can verify that your published rules and runtime behavior are consistent, surfacing misconfigurations before they are exploited.

Frequently Asked Questions

How does Firestore’s native security model interact with Hanami’s authorization layer?
Firestore security rules enforce access at the database path level, while Hanami’s authorization operates at the application level. Both must agree: rules should scope paths by authenticated user identifiers (e.g., users/{userId}/...), and Hanami must validate that the current user matches the identifier used in the Firestore path before issuing reads or writes.
What are common misconfigurations that lead to Broken Access Control in Firestore-backed Hanami apps?
Common misconfigurations include rules that rely only on request.auth != null without checking ownership, permissive wildcard rules left from prototyping, and predictable document IDs that allow enumeration. These allow authenticated users to manipulate IDs and access data that should be restricted by Hanami’s business logic.