Credential Stuffing in Hanami with Bearer Tokens
Credential Stuffing in Hanami with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Credential stuffing is an automated attack where previously breached username and password pairs are reused to gain unauthorized access. In Hanami, when authentication relies on Bearer tokens issued without additional checks, this pattern becomes especially risky. Bearer tokens are typically sent in the Authorization header as Authorization: Bearer <token>. If token issuance is tied only to static credentials (e.g., username/password) and lacks binding to client context, an attacker can replay stolen tokens across accounts.
Hanami applications that issue Bearer tokens after simple credential validation may inadvertently enable token reuse across users. Without per-request origin validation or token binding, a token obtained via legitimate login can be replayed from different IPs, user agents, or locations. Because Bearer tokens are long-lived by default in many implementations, stolen tokens remain valid until expiration, giving attackers extended windows to automate login attempts against multiple endpoints.
The combination is dangerous because Hanami’s routing and controller logic often trusts the Authorization header implicitly. If token validation does not include nonce, timestamp, or scope checks, attackers can use automated scripts to test credentials at scale. Session fixation and token replay are common patterns; for example, a compromised token like eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE5OTk5OTk5OTl9.example can be reused across requests until revoked. Hanami’s middleware stack may not enforce strict token binding to the original authentication context, allowing attackers to iterate through user accounts without triggering account lockout.
Credential stuffing against Bearer token endpoints also bypasses traditional login throttling if token issuance does not rate-limit credential verification attempts. Attackers probe many usernames with known breached passwords, and if Hanami responds with 200 OK and a new token rather than 401, they infer valid credentials. This exposes user accounts and potentially elevates privileges if the issued token inherits broader permissions.
To detect such issues, middleBrick scans unauthenticated attack surfaces and flags missing binding between token issuance and client context. Its LLM/AI Security checks specifically probe for prompt injection risks in authentication workflows, while standard API checks identify weak token validation and missing rate limiting on credential endpoints. Findings map to OWASP API Top 10 and PCI-DSS requirements, providing prioritized remediation guidance rather than attempting automatic fixes.
Bearer Tokens-Specific Remediation in Hanami — concrete code fixes
Remediation focuses on ensuring Bearer tokens are issued only when the request context is tightly bound to the authenticated user and cannot be reused indiscriminately. Below are concrete patterns in Hanami that reduce risk.
- Include client fingerprint in token claims: bind the token to the request’s IP user agent hash and validate on each use.
- Shorten token lifetimes and use refresh tokens with strict rotation to reduce replay windows.
- Enforce strict rate limiting on token issuance endpoints to slow down automated credential testing.
- Require scope and nonce checks for sensitive operations, ensuring tokens are not accepted generically.
Example Hanami command object that issues a Bearer token with client binding:
module Auth
class IssueToken
def initialize(user, request)
@user = user
@request = request
end
def call
token_payload = {
sub: @user.id,
scope: 'api:read api:write',
client_fingerprint: fingerprint,
iat: Time.now.to_i,
exp: (Time.now + 30.minutes).to_i
}
JWT.encode(token_payload, ENV['JWT_SECRET_KEY'], 'HS256')
end
private
def fingerprint
# Bind token to client context
Digest::SHA256.hexdigest("#{@request.ip}|#{@request.user_agent}")
end
end
end
Example Hanami controller that validates Bearer token and checks client fingerprint:
module Api
class BaseController < Hanami::Action
def authenticate!
token = request.authorization&.split(' ')&.last
halt 401, { error: 'unauthorized' }.to_json unless token
begin
decoded = JWT.decode(token, ENV['JWT_SECRET_KEY'], true, algorithm: 'HS256')
payload = decoded.first
unless payload['client_fingerprint'] == current_fingerprint
halt 401, { error: 'invalid_token_binding' }.to_json
end
@current_user = UserRepository.new.find(payload['sub'])
rescue JWT::ExpiredSignature, JWT::DecodeError
halt 401, { error: 'invalid_token' }.to_json
end
end
def current_fingerprint
Digest::SHA256.hexdigest("#{request.ip}|#{request.user_agent}")
end
end
end
Example Hanami configuration for rate limiting token issuance to mitigate credential stuffing:
use Rack::Attack
Rack::Attack.throttle('token/rate/ip', limit: 5, period: 60) do |req|
req.ip if req.path == '/api/auth/token' && req.post?
end
middleBrick’s CLI can be used to verify these patterns by scanning your endpoint unauthenticated and checking whether token validation includes binding and rate limiting. Its dashboard tracks scores over time, while the GitHub Action can fail builds if risk scores degrade. The MCP Server allows you to run these checks directly from your IDE when modifying authentication flows.