HIGH auth bypasshanamihmac signatures

Auth Bypass in Hanami with Hmac Signatures

Auth Bypass in Hanami with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Hanami applications that use Hmac Signatures for request authentication can be vulnerable to authentication bypass when the signature verification logic is incomplete or misaligned with the runtime behavior of the framework. In a typical setup, the client computes an Hmac over selected parts of the request (method, path, selected headers, and body) using a shared secret, and sends the signature in a custom header such as x-api-signature. The server recomputes the Hmac using the same algorithm and secret, then compares the two signatures. If the comparison is performed incorrectly—such as using a non-constant-time comparison, failing to normalize whitespace, or including or excluding elements inconsistently—an attacker can craft inputs that produce the same signature (collision) or exploit timing differences to infer information about the valid signature.

In Hanami, a common pattern is to compute the Hmac over the request payload and a deterministic subset of headers, then verify the signature in a before action or a custom middleware. However, if the application does not explicitly include the HTTP method and the request path in the signed payload, or if it includes query parameters inconsistently between client and server, the signature can be reused across different endpoints or methods. This inconsistency effectively decouples the signature from the intended resource and action, allowing an authenticated-looking request to a different endpoint to be accepted as valid. For example, a signature computed for POST /admin/users without the path may be accepted by the server when presented to POST /admin/roles, provided the body and selected headers match, leading to privilege escalation or unauthorized operations.

Another specific vector arises when Hanami applications parse JSON bodies and then serialize them differently for signature verification (e.g., differing key ordering, inclusion or exclusion of null values, or handling of nested objects). If the server normalizes the payload one way and the client another, a valid signature on one side may not match on the other, prompting developers to disable strict payload checks or to fall back to a more permissive comparison. Such permissiveness can open the door to signature collision attacks or allow an attacker to supply additional parameters that are ignored during verification but alter server behavior, a pattern that overlaps with BOLA/IDOR when object ownership is inferred from the payload rather than from a secure context. The vulnerability is compounded when the Hmac is the only authentication mechanism and there is no binding to a specific scope, such as tenant ID or user ID, within the signed data.

Runtime factors can also exacerbate the issue. For instance, if the shared secret is stored in an environment variable that is accidentally exposed through logs or error messages, or if the secret is rotated infrequently, an attacker who obtains a single valid signature and knows the algorithm can replay it across a window of validity. Because Hanami does not enforce a strict timestamp or nonce by default in such custom signature schemes, replay attacks become feasible, especially if the application does not implement rate limiting or idempotency checks at the endpoint level. The combination of weak canonicalization, missing binding to the request target, and lack of replay protection creates a practical authentication bypass scenario that an attacker can exploit using intercepted traffic or compromised client-side code.

Hmac Signatures-Specific Remediation in Hanami — concrete code fixes

To remediate authentication bypass risks when using Hmac Signatures in Hanami, align the signing and verification logic precisely, bind the signature to the full request context, and use secure comparison patterns. Below is a minimal, secure Hanami service object that computes and verifies an Hmac over the HTTP method, request path, selected headers, and a canonical JSON body. The example uses OpenSSL for Hmac-SHA256 and ActiveSupport::SecurityUtils.secure_compare to prevent timing attacks.

require 'openssl'
require 'active_support/security_utils'

class HmacSignatureService
  ALGORITHM = 'sha256'
  SECRET = ENV.fetch('API_HMAC_SECRET') { raise 'Missing HMAC secret' }

  def self.compute(method, path, headers_to_sign, body)
    payload = canonical_payload(method, path, headers_to_sign, body)
    OpenSSL::HMAC.hexdigest(ALGORITHM, SECRET, payload)
  end

  def self.verify(method, path, headers_to_sign, body, received_signature)
    computed = compute(method, path, headers_to_sign, body)
    ActiveSupport::SecurityUtils.secure_compare(computed, received_signature)
  end

  private

  def self.canonical_headers(headers_to_sign)
    headers_to_sign.sort.map { |k, v| "#{k.downcase}:#{v.strip}" }.join('|')
  end

  def self.canonical_payload(method, path, headers_to_sign, body)
    [method.upcase, path, canonical_headers(headers_to_sign), body].join("\n")
  end
end

In your Hanami controller or action, ensure the method, path, and a deterministic set of headers are included in the verification. For JSON payloads, canonicalize the body by sorting keys and excluding non-validated fields before verification.

class Api::V1::BaseController < Hanami::Controller
  before do
    method = request.request_method
    path   = request.path.to_s
    headers = select_headers_for_signing(request.headers)
    body   = request.body.read
    request.body.rewind

    signature_header = request.headers['x-api-signature']
    unless HmacSignatureService.verify(method, path, headers, body, signature_header)
      raise Hanami::Action::UnauthorizedError, 'Invalid signature'
    end
  end

  private

  def select_headers_for_signing(headers)
    # Be explicit about which headers are included in the Hmac
    { 'content-type' => headers['content-type'], 'x-request-id' => headers['x-request-id'] }
  end
end

To prevent replay and binding issues, include a timestamp and nonce in the signed payload if you require replay protection at the Hmac layer, and validate freshness server-side. Also bind the signature to a tenant or user identifier so that signatures cannot be reused across scopes. Avoid including sensitive or mutable fields in the canonical body; instead, use stable identifiers and explicit field selection. Periodically rotate the shared secret and store it securely, and enforce transport-layer protections to reduce the risk of secret leakage. These steps ensure that Hmac Signatures in Hanami provide a robust binding between the request context and the authentication decision.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

What causes Hmac Signature verification to fail and enable bypass in Hanami?
Bypass can occur when the signature is computed over an inconsistent set of request elements (e.g., missing HTTP method or path), uses a non-constant-time comparison, or allows differences in body canonicalization between client and server. Missing binding to tenant or user scope and lack of replay protection also weaken authentication.
How can I securely bind Hmac Signatures to a specific user or tenant in Hanami?
Include a stable user_id or tenant_id in the signed payload and verify it server-side so signatures cannot be reused across subjects. Ensure the Hmac covers method, path, selected headers, canonical body, and the binding identifier, and use secure comparison to prevent timing attacks.