HIGH cache poisoninghanamifirestore

Cache Poisoning in Hanami with Firestore

Cache Poisoning in Hanami with Firestore — how this specific combination creates or exposes the vulnerability

Cache poisoning in a Hanami application that uses Google Cloud Firestore as a persistence layer occurs when attacker-influenced data is stored in or retrieved from the cache and subsequently used to influence behavior, leak information, or bypass authorization checks. Hanami’s architecture encourages explicit, domain-driven models and service objects; if these services read from caches keyed by untrusted input and then write Firestore entities into that cache, an attacker can manipulate keys, query parameters, or HTTP headers to cause the application to cache and later serve malicious or incorrect data.

Consider a Hanami service that caches Firestore documents by a user-controlled document ID or a path parameter. If the cache key is derived directly from this input without strict validation, an attacker can cause the application to store a poisoned cache entry under a key that other users or privileged workflows later read. For example, an attacker might supply a document ID like users/attacker__admin and, if Firestore permissions are misconfigured or overly permissive, cause the cached read to return data that should remain private. Because Firestore rules are evaluated at read/write time, a cached response that bypasses proper context (such as missing authentication headers or a misapplied emulator mode) can persist incorrect authorization decisions across requests.

The risk is compounded when Firestore emulator configurations or environment-based cache backends are used without proper isolation. In development or testing environments, developers might run the Firestore emulator locally and inadvertently rely on cached data that was populated against a production-like dataset. An attacker who can influence cache keys or cache-control directives might cause Hanami to serve sensitive Firestore entities from the cache to unauthorized clients. Moreover, if cache entries include Firestore document references or tokens, those references can be leveraged in SSRF or privilege-escalation patterns when the cached data is later deserialized and used to construct further Firestore queries.

Because middleBrick tests unauthenticated attack surfaces and checks integrations like Firestore for data exposure and insecure configurations, it can surface cache-poisoning risks that stem from improper key construction, missing input validation, and weak separation between tenant or user contexts. This is particularly important for Hanami services that combine Firestore’s flexible document model with aggressive caching strategies, as inconsistent rule sets and cache invalidation logic can lead to information leakage or inconsistent authorization enforcement.

Firestore-Specific Remediation in Hanami — concrete code fixes

Remediation focuses on strict input validation, canonical cache-key construction, and scoping Firestore reads to the correct tenant and user context. Avoid using raw user input as cache keys; instead, derive keys from authenticated identifiers and normalized paths. Hanami’s entity objects provide a stable basis for this: use the entity’s type and normalized ID to build cache keys, and ensure the Firestore document ID is validated against an allowlist or a strict pattern before use.

Example: a Hanami service that reads a Firestore document safely and caches the result with a canonical key.

require "google/cloud/firestore"
require "digest"

class FirestoreDocumentFetcher
  def initialize(entity_name, entity_id)
    @entity_name = entity_name
    @entity_id = entity_id
    @firestore = Google::Cloud::Firestore.new
    @collection = @firestore.collection(entity_name)
  end

  def call
    canonical_id = validate_and_normalize_id(@entity_id)
    cache_key = "firestore:#{@entity_name}:#{canonical_id}:v1"
    cached = Cache.get(cache_key)
    return cached if cached

    doc = @collection.document(canonical_id).get
    raise NotFoundError, "Document does not exist" unless doc.exists?

    data = doc.data.merge("id" => canonical_id)
    Cache.write(cache_key, data, expires_in: 300)
    data
  end

  private

  def validate_and_normalize_id(input)
    # Allow only alphanumeric, hyphens, and underscores; reject path traversal or collection-like strings
    unless input&.match?(\A[\w\-]+\z)
      raise ArgumentError, "Invalid document ID"
    end
    # Ensure the ID does not contain path-like segments
    raise ArgumentError, "Invalid document ID" if input.include?("/")
    input
  end
end

Example: a Hanami command that writes Firestore data with tenant scoping and strict ID validation.

class UpdateUserPreferences
  def initialize(current_user, params)
    @current_user = current_user
    @params = params
    @firestore = Google::Cloud::Firestore.new
  end

  def call
    tenant_id = @current_user.tenant_id
    user_id = @current_user.id
    # Canonical, scoped path; never trust client-supplied document paths
    doc_ref = @firestore.collection("tenants").document(tenant_id).collection("users").document(user_id)

    # Validate incoming keys; only allow expected preference keys
    allowed = %w[theme notifications language]
    updates = @params.slice(*allowed)

    doc_ref.update(updates)
    # Invalidate any cached entries for this user by namespacing the cache key
    Cache.delete("firestore:users:#{tenant_id}:#{user_id}:profile")
    { status: :ok }
  end
end

Additional measures include enforcing Firestore security rules that explicitly scope reads and writes to the requesting user or tenant, avoiding emulator endpoints in production cache configurations, and ensuring cache entries do not contain raw Firestore document references or tokens. middleBrick’s checks for data exposure and property authorization can help detect misconfigurations that would otherwise enable cache poisoning across Firestore-backed Hanami services.

Frequently Asked Questions

How can I tell if my Hanami app’s cache keys are vulnerable to cache poisoning when using Firestore?
Review your code for cache keys that incorporate unvalidated user input or Firestore document IDs directly. Use middleBrick to scan your API; it checks data exposure and property authorization and can surface risks where cached data may be influenced by attacker-controlled keys or Firestore rules that are too permissive.
Is it safe to cache Firestore documents in Hanami if I use short TTLs?
Short TTLs reduce the window of impact but do not eliminate cache poisoning. You must still validate and canonicalize cache keys, enforce Firestore rules, and ensure cached content does not contain sensitive references that could be poisoned. Combine short TTLs with strict input validation and tenant-aware scoping.