HIGH identification failuresgrapefirestore

Identification Failures in Grape with Firestore

Identification Failures in Grape with Firestore — how this specific combination creates or exposes the vulnerability

Identification failures occur when an API does not properly ensure that a subject can be accurately and reliably identified before authorization and data access decisions are made. In a Grape API backed by Cloud Firestore, this typically manifests as missing or inconsistent identity checks on incoming requests, allowing attackers to manipulate identifiers or bypass ownership checks.

Grape is a REST-like API micro-framework for Ruby, often used to expose domain logic as endpoints. Firestore is a NoSQL document store with security rules that enforce access at the database level. When these two are combined, identification failures arise if the application layer passes user-supplied identifiers (e.g., user_id, document_id) into Firestore queries without first validating identity context. For example, an endpoint like GET /users/:user_id/records/:record_id might directly forward params[:user_id] into a Firestore query such as Firestore.doc("users/#{params[:user_id]}/records/#{params[:record_id]}"). If the API does not confirm that the authenticated subject’s identity matches params[:user_id], an attacker can tamper with the parameter to access another user’s records.

Firestore security rules rely on request.auth to identify a caller. If the Grape layer fails to propagate a reliable identity into the authenticated context (for example, by not validating a token or session before constructing Firestore references), rules may evaluate against an anonymous or spoofed auth object. This can lead to Insecure Direct Object References (IDOR) or Broken Object Level Authorization (BOLA), where one user can read or modify another user’s data simply by changing an identifier in the request.

Additionally, Firestore’s document paths are predictable. Without proper identification checks, an attacker can enumerate IDs and probe endpoints for existence and permissions. For instance, iterating over numeric document IDs in users/{uid}/records/{rid} becomes trivial if the API does not enforce that each record belongs to the requesting user. Real-world attack patterns such as IDOR (CWE-639) and authorization bypass (CWE-285) are commonly observed in this configuration when identification is treated as optional or implicit rather than explicit and verified.

middleBrick scans identify such risks under the BOLA/IDOR and Authentication checks, highlighting cases where endpoints use identifiers without verifying they belong to the authenticated subject. The scanner also checks the unauthenticated attack surface, which can reveal endpoints that inadvertently expose data when identification is weak or missing.

Firestore-Specific Remediation in Grape

Remediation centers on ensuring the authenticated subject’s identity is verified and used consistently when constructing Firestore references. Do not rely on client-supplied identifiers alone; derive identifiers from the authenticated context and enforce ownership at the data-access layer.

First, validate the identity from the authentication token or session and map it to a Firestore UID. Then use that UID to build document paths and security rule-friendly references. Below is a secure Grape endpoint example that retrieves a user-specific record only when the subject matches.

# config/initializers/firestore.rb (setup)
require "google/cloud/firestore"

Firestore.configure do |config|
  config.project = ENV["FIRESTORE_PROJECT_ID"]
  config.credentials = Google::Auth::ServiceAccountCredentials.make_creds(
    json_key_io: File.open(ENV["FIRESTORE_KEY_PATH"]),
    scope: "https://www.googleapis.com/auth/datastore"
  )
end

# app/api/v1/records.rb
require "firebase_auth"

class RecordsAPI < Grape::API
  format :json
  before { authenticated? }

  helpers do
    def current_user
      @current_user ||= begin
        token = request.env["HTTP_AUTHORIZATION"]&.to_s.gsub(/^Bearer\s+/, "")
        FirebaseAuth.verify_id_token(token) if token
      end
    end

    def authenticated?
      error!("Unauthorized", 401) unless current_user
    end

    def firestore
      @firestore ||= Google::Cloud::Firestore.new
    }

    # Safe document reference using authenticated UID
    def user_record_path(user_id, record_id)
      "users/#{user_id}/records/#{record_id}"
    end
  end

  get "/users/:user_id/records/:record_id" do
    # Use the authenticated user’s UID, not the URL param
    user_id = current_user["uid"]
    record_id = params[:record_id]
    doc_ref = firestore.doc(user_record_path(user_id, record_id))
    snapshot = doc_ref.get

    error!("Record not found", 404) unless snapshot.exists?

    {
      id: snapshot.id,
      data: snapshot.data
    }
  end
end

# Firestore security rules (complementary enforcement)
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{uid}/records/{recordId} {
      allow read: if request.auth != null && request.auth.uid == uid;
      // additional write rules as needed
    }
  }
}

Key points in the remediation:

  • Derive user_id from current_user["uid"] obtained after verifying the authentication token, rather than trusting params[:user_id].
  • Construct Firestore document paths using the authenticated UID to ensure the subject and the resource are bound correctly.
  • Keep Firestore security rules as a safety net, but do not rely on them alone to enforce identification; the application layer must prevent ID manipulation.
  • For operations involving client-supplied IDs (e.g., creating records), map the client ID to the authenticated UID server-side before writing to Firestore, avoiding direct use of user-controlled path segments.

middleBrick’s LLM/AI Security checks can detect scenarios where endpoints interact with external models or expose sensitive contexts, and its BOLA/IDOR analysis will highlight endpoints that do not bind identifiers to authenticated identity. The scanner also reviews Data Exposure and Encryption checks to ensure that identifiers and tokens are not leaked in logs or responses.

Frequently Asked Questions

How can I verify that my Grape endpoints are correctly identifying users before accessing Firestore?
Ensure authentication is enforced on each endpoint, derive user identifiers from verified tokens (e.g., Firebase ID token), and use those identifiers to build Firestore document paths. Avoid using raw client-supplied IDs in queries. middleBrick scans can flag endpoints where identifiers are used without proper authentication binding.
What should I do if Firestore rules rely on request.auth but my Grape app does not validate identity?
Validate identity in the API layer before constructing any Firestore references. Map authenticated subject attributes (such as UID) into paths and enforce ownership checks. If request.auth is missing or mismatched, reject the request with 401. middleBrick’s Authentication and BOLA/IDOR checks will highlight missing identity validation.