Auth Bypass in Hapi
How Auth Bypass Manifests in Hapi
Auth bypass in Hapi applications typically exploits misconfigurations in the authentication and authorization pipeline. The most common attack vectors involve incomplete route protection, improper validation of authentication strategies, and timing-based attacks on token verification.
One prevalent pattern occurs when developers assume that registering an authentication strategy automatically protects all routes. Consider this vulnerable Hapi setup:
const Hapi = require('@hapi/hapi');
const server = Hapi.server({ port: 3000 });
// Authentication strategy registered but not applied to routes
const init = async () => {
await server.register(require('@hapi/basic'));
server.auth.strategy('simple', 'basic', { validate });
server.auth.default('simple'); // This doesn't protect pre-existing routes
server.route({
method: 'GET',
path: '/public',
handler: (request, h) => 'Public data'
});
server.route({
method: 'GET',
path: '/private',
handler: (request, h) => 'Private data'
});
await server.start();
};
The vulnerability here is that server.auth.default() only affects routes registered after it's called. Any route defined beforehand remains unprotected, creating an auth bypass window.
Another critical Hapi-specific vulnerability involves scope-based authorization bypass. When using scope validation without proper hierarchical checking:
server.auth.strategy('jwt', 'jwt', {
key: process.env.JWT_SECRET,
validate: validateUser,
verifyOptions: { algorithms: ['HS256'] }
});
server.route({
method: 'GET',
path: '/admin',
options: {
auth: {
strategy: 'jwt',
access: [{ scope: 'admin' }]
}
},
handler: (request, h) => 'Admin data'
});
An attacker with a 'user' scope token might bypass this if the validation function doesn't properly check scope hierarchies or if the token's scope field is manipulated to include 'admin' through JSON parsing vulnerabilities.
Time-of-check to time-of-use (TOCTOU) race conditions in Hapi's authentication flow can also enable auth bypass. This occurs when token validation and subsequent authorization checks aren't atomic:
// Vulnerable: separate validation and authorization
async function handler(request, h) {
const token = request.headers.authorization;
const user = await validateToken(token);
// TOCTOU window between validation and usage
if (user && user.active) {
return await getUserData(user.id);
}
}
During the window between token validation and data access, the user's status could change, allowing unauthorized access if the application doesn't re-validate permissions before sensitive operations.
Hapi-Specific Detection
Detecting auth bypass vulnerabilities in Hapi requires examining both the authentication configuration and runtime behavior. middleBrick's scanner specifically targets Hapi's authentication architecture with these checks:
Authentication Strategy Coverage Analysis - The scanner verifies that all routes have appropriate authentication strategies applied. It detects routes defined before server.auth.default() is called and routes missing explicit authentication configuration:
# Using middleBrick CLI to scan Hapi API
middlebrick scan https://api.example.com --target hapi
The scanner examines route registration patterns and identifies unprotected endpoints that should be behind authentication.
Scope Validation Testing - middleBrick actively tests scope-based authorization by attempting requests with various scope combinations. It checks for improper scope validation that might allow privilege escalation:
// Scanner tests these attack patterns
const testScopes = [
'', // Empty scope
'user', // Lower privilege
'admin,user', // Scope injection attempt
'admin user' // Null byte injection
];
Authentication Bypass via Route Precedence - Hapi allows route-specific authentication to override server-level defaults. The scanner detects when route-specific auth configurations weaken overall security:
// Vulnerable: route-specific auth weakening protection
server.auth.default('secure-strategy');
server.route({
method: 'GET',
path: '/weak',
options: { auth: false }, // Bypasses default
handler: (request, h) => 'Bypassed data'
});
Plugin Authentication Integration Testing - Hapi's plugin architecture can introduce auth bypass vulnerabilities when plugins register routes without proper authentication awareness. The scanner analyzes plugin route registrations and their authentication context.
Token Validation Race Condition Detection - While runtime race conditions are difficult to detect statically, middleBrick identifies code patterns that create TOCTOU vulnerabilities by analyzing the authentication flow and suggesting atomic validation patterns.
Hapi-Specific Remediation
Securing Hapi applications against auth bypass requires systematic application of authentication best practices specific to Hapi's architecture. Here are Hapi-native solutions:
Centralized Authentication Registration - Always register authentication strategies before defining any routes to ensure complete coverage:
const init = async () => {
await server.register(require('@hapi/basic'));
server.auth.strategy('simple', 'basic', { validate });
server.auth.default('simple');
// Now all routes are protected
server.route([...]);
};
Route-Specific Authentication with Validation - For routes requiring different authentication levels, use explicit configuration with validation:
server.route({
method: 'GET',
path: '/admin',
options: {
auth: {
strategy: 'jwt',
access: {
scope: ['admin'],
entity: 'user'
}
}
},
handler: (request, h) => {
// Additional runtime validation
if (!request.auth.credentials.admin) {
throw Boom.forbidden('Insufficient privileges');
}
return 'Admin data';
}
});
Atomic Authentication and Authorization - Combine token validation and permission checks in a single atomic operation:
async function atomicAuthHandler(request, h) {
const token = request.headers.authorization;
// Single atomic operation
const result = await validateAndAuthorize(token, request.path);
if (!result.authorized) {
throw Boom.unauthorized('Authentication failed');
}
return await result.handler(request, h);
}
Scope Validation with Hierarchical Checking - Implement proper scope validation that prevents scope injection:
function validateScopes(required, provided) {
// Prevent scope injection via array manipulation
const requiredSet = new Set(required);
const providedSet = new Set(provided);
// Check if all required scopes are present
for (const scope of requiredSet) {
if (!providedSet.has(scope)) {
return false;
}
}
// Prevent privilege escalation via extra scopes
for (const scope of providedSet) {
if (!requiredSet.has(scope) && scope !== 'user') {
return false; // Extra non-user scope detected
}
}
return true;
}
Plugin Authentication Awareness - When developing Hapi plugins that register routes, always respect the parent server's authentication configuration:
const plugin = {
name: 'secure-plugin',
version: '1.0.0',
register: async (server, options) => {
server.route({
method: 'GET',
path: '/plugin-route',
options: {
auth: options.auth || server.settings.app.defaultAuth
},
handler: (request, h) => 'Plugin data'
});
}
};
Authentication Testing in CI/CD - Integrate middleBrick scanning into your Hapi development workflow to catch auth bypass vulnerabilities early:
# GitHub Action for Hapi API security
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run middleBrick scan
run: |
npx middlebrick scan ${{ secrets.API_URL }} --target hapi
continue-on-error: true
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 |