HIGH cache poisoninghanamiruby

Cache Poisoning in Hanami (Ruby)

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

Cache poisoning in Hanami (a Ruby web framework) occurs when an attacker manipulates cache keys or stored responses so that malicious content is served to other users. Because Hanami encourages explicit, developer-controlled caching and relies on Ruby objects for key generation, misconfigured caching logic can reflect attacker input into cache entries.

Three dimensions contribute to the risk in this stack:

  • Language: Ruby’s flexible hash keys and string interpolation make it easy to build cache keys from untrusted sources if input is not strictly validated or normalized.
  • Framework: Hanami’s architecture promotes use of repositories and view models; if caching is applied at the view or query level without normalizing parameters, an attacker can inject crafted query parameters that change cache entries.
  • Application logic: Features such as per-user or per-tenant caching that incorporate identifiers from requests (e.g., subdomain, path, or headers) can inadvertently store responses keyed by attacker-controlled values, leading to cross-user contamination.

For example, using request parameters directly in cache keys without sanitization can cause an attacker to poison the cache for subsequent users. Consider a Hanami view that caches a rendered fragment based on a URL query parameter without validation:

module Web::Views::Items
  class Show
    include Hanami::View

    def call(params)
      cache_key = "items/show?category=#{params[:category]}"
      cached = cache.fetch(cache_key) do
        # ... render item list
      end
      # ... response
    end
  end
end

If params[:category] contains user-controlled input and is used verbatim, two different attackers can cause the application to cache and later serve different content under the same key. This can lead to data leakage or incorrect content being served.

Another scenario involves caching HTTP responses or fragments that include sensitive headers or cookies inadvertently reflected into cache storage. Hanami’s default caching integrations do not automatically strip sensitive inputs; developers must ensure that only safe, canonical parameters participate in cache key construction.

Because Hanami applications often compose multiple layers (repositories, entities, views), improper caching at any layer can propagate poisoned entries. Regular scanning with a tool like middleBrick can surface these risks by checking for missing input validation, weak cache-key construction, and improper data exposure in cached responses.

Ruby-Specific Remediation in Hanami

Remediation focuses on strict input validation, canonical normalization, and isolating cache keys from untrusted data. Below are concrete, Ruby-specific fixes tailored for Hanami applications.

  • Validate and sanitize inputs: Ensure all inputs that influence cache behavior are validated against an allowlist and normalized.
  • Use canonical keys: Build cache keys from normalized, non-user-controlled segments where possible, or hash user input before inclusion.
  • Scope cache by tenant and user safely: If caching per user or tenant, use server-side identifiers rather than raw request values.

Example 1: Safe cache key construction

Instead of directly interpolating parameters, sanitize and hash them:

require "digest"

module Web::Views::Items
  class Show
    include Hanami::View

    def call(params)
      category = params[:category].to_s.strip.downcase
      # Allowlist validation
      allowed_categories = %w[books electronics food]
      unless allowed_categories.include?(category)
        category = "default"
      end
      # Canonical, hashed key
      cache_key = "items/show/#{Digest::SHA256.hexdigest(category)}"
      cached = cache.fetch(cache_key) do
        # ... render item list
      end
      # ... response
    end
  end
end

Example 2: Scoped caching with a canonical identifier

When caching per user or tenant, use a server-side ID and avoid injecting raw request values:

module Web::Views::Dashboard
  class Profile
    include Hanami::View

    def call(current_account)
      # current_account is a server-side entity with a stable ID
      cache_key = "account/#{current_account.id}/profile"
      cached = cache.fetch(cache_key) do
        # ... render profile
      end
      # ... response
    end
  end
end

Example 3: Middleware-level normalization (optional pattern)

For applications that need to enforce canonical request shapes before caching, use a Hanami middleware or service object to normalize parameters:

class CacheKeyNormalizer
  def initialize(app)
    @app = app
  end

  def call(env)
    req = Rack::Request.new(env)
    # Normalize query parameters used for caching
    if req.get? && req.params["category"]
      req.params["category"] = req.params["category"].strip.downcase
    end
    @app.call(env)
  end
end

Register the middleware in your Hanami application configuration if you choose this approach. These patterns reduce the risk of cache poisoning by ensuring that only validated, canonical data influences cache storage.

Frequently Asked Questions

How can I detect cache poisoning risks in my Hanami app using middleBrick?
Run a scan with middleBrick against your public API endpoints. The tool checks input validation and cache-key construction patterns; findings include missing input sanitization and references to the OWASP API Top 10 and relevant CVEs where applicable.
Does middleBrick fix cache poisoning issues automatically?
middleBrick detects and reports findings with remediation guidance; it does not automatically fix or patch your code. Use the provided guidance to update cache-key logic and input handling in Hanami.