Auth Bypass in Sinatra with Bearer Tokens
Auth Bypass in Sinatra with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Sinatra is a lightweight Ruby web framework that does not enforce authentication by default. When developers add Bearer token handling without rigorous validation and scoping, they can inadvertently create an auth bypass. This typically occurs when token verification is incomplete, overly permissive, or applied inconsistently across routes.
One common pattern is reading the token from the Authorization header and proceeding without confirming the token’s intended audience (aud) or scope. For example, a handler that extracts the token but does not validate its signature or expiration can be tricked into accepting an unsigned or expired token as valid. Additionally, if route-level before filters are missing or conditionally bypassed (for instance, allowing unauthenticated access to certain paths), an attacker can reach authenticated endpoints by omitting the Authorization header entirely or by using a token issued for a different resource.
Middleware or helper methods that normalize tokens incorrectly can also contribute to bypass. If the code downcases or trims tokens in a way that produces collisions, or if multiple token formats are accepted without strict validation, an attacker may supply an alternate string that passes the check. Another vector is failing to protect token introspection or validation endpoints themselves, which can allow an attacker to probe the API to discover valid tokens or weak validation logic.
In the context of API security scanning, these issues map to the BOLA/IDOR and Authentication checks. An unauthenticated or under-authenticated endpoint that exposes sensitive data or actions without proper authorization is flagged with high severity. The scanner tests whether endpoints correctly reject requests lacking a valid Bearer token and whether tokens are validated in a way that prevents substitution or tampering.
Real-world attack patterns include using a token from a low-privilege account to access high-privilege endpoints, or leveraging missing scope checks to perform actions outside the token’s intended permissions. These map to common weaknesses enumerated in the OWASP API Security Top 10, particularly Broken Object Level Authorization and Security Misconfiguration. The presence of these flaws can also intersect with other checks such as Property Authorization and Input Validation when token misuse leads to unauthorized data exposure or injection-like behaviors.
Bearer Tokens-Specific Remediation in Sinatra — concrete code fixes
Remediation centers on strict token validation, consistent enforcement, and minimizing implicit trust. Below are concrete Sinatra examples that demonstrate secure handling of Bearer tokens.
1. Centralized before filter with strict validation
Use a before filter that runs on protected routes, validates the token format, verifies the signature, checks expiration (exp), audience (aud), and scope, and rejects requests that do not meet these criteria.
require 'sinatra'
require 'jwt'
require 'json'
class SecureApp < Sinatra::Base
TOKEN_AUDIENCE = 'my-api.example.com'
TOKEN_ISSUER = 'https://auth.example.com/'
helpers do
def current_user
@current_user
end
def authenticate!
auth_header = request.env['HTTP_AUTHORIZATION']
halt 401, { error: 'missing_token', message: 'Authorization header required' }.to_json unless auth_header
token = auth_header.to_s.sub(/^Bearer\s+/, '')
halt 401, { error: 'invalid_token', message: 'Malformed Authorization header' }.to_json unless token && !token.empty?
# Validate token structure and claims
begin
decoded = JWT.decode(
token,
ENV.fetch('JWT_PUBLIC_KEY'),
true,
{
algorithm: 'RS256',
iss: TOKEN_ISSUER,
aud: TOKEN_AUDIENCE,
verify_expiration: true
}
)
@current_user = decoded.first['sub']
rescue JWT::ExpiredSignature
halt 401, { error: 'token_expired', message: 'Access token has expired' }.to_json
rescue JWT::VerificationError, JWT::DecodeError
halt 401, { error: 'invalid_token', message: 'Token signature or claims invalid' }.to_json
end
end
end
before do
content_type :json
end
get '/api/me' do
authenticate!
{ user_id: current_user, scope: 'read:profile' }.to_json
end
end
2. Explicit scope checks for fine-grained authorization
After authentication, verify that the token includes the required scope for the requested action. This prevents privilege escalation when a token lacks necessary permissions.
helpers do
def require_scope!(required)
token = request.env['HTTP_AUTHORIZATION']&.to_s&.sub(/^Bearer\s+/, '')
halt 403, { error: 'insufficient_scope', message: "Missing required scope: #{required}" }.to_json unless token
decoded = JWT.decode(
token,
ENV.fetch('JWT_PUBLIC_KEY'),
true,
{
algorithm: 'RS256',
aud: TOKEN_AUDIENCE,
verify_expiration: true
}
)
scopes = decoded.first['scope']
scopes = scopes.split if scopes.is_a?(String)
halt 403, { error: 'insufficient_scope', message: "Required scope not granted" }.to_json unless scopes&.include?(required)
end
end
get '/api/admin' do
authenticate!
require_scope!('admin')
{ admin: true }.to_json
end
3. Reject malformed and duplicated tokens consistently
Ensure that token normalization does not introduce equivalences that bypass checks. Do not perform case-insensitive comparisons or strip whitespace in ways that could produce different logical tokens. Reject tokens with invalid characters early.
before '/api/*' do
authenticate!
end
# Reject tokens containing whitespace or obviously malformed segments
before do
token = request.env['HTTP_AUTHORIZATION']&.to_s
if token&.include?(' ') || token&.include?("\t")
halt 400, { error: 'bad_request', message: 'Token must not contain whitespace' }.to_json
end
end
4. Protect introspection and token validation endpoints
If you provide endpoints for token introspection or revocation, apply the same strict validation and scope checks, and avoid leaking information via timing differences or verbose error messages.
post '/token/introspect' do
authenticate!
target_token = params['token']
halt 400, { error: 'invalid_request', message: 'Token parameter required' }.to_json unless target_token
# Perform internal introspection securely without revealing user details to unauthorized callers
valid, reason = secure_introspect(target_token)
if valid
{ active: true }.to_json
else
halt 401, { active: false, error: 'invalid_token', error_description: reason }.to_json
end
end
5. MiddleBrick integrations
You can use the CLI to validate your Sinatra API’s behavior: middlebrick scan <url>. If you prefer automation in development, the GitHub Action adds API security checks to your CI/CD pipeline and can fail builds if risk scores exceed your threshold. For AI-assisted workflows, the MCP Server lets you scan APIs directly from your coding assistant.
Findings from scans will highlight missing token validation, inconsistent enforcement, and potential BOLA/IDOR paths. Use the prioritized findings and remediation guidance to tighten validation, enforce scopes, and ensure each route correctly requires authentication.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |