Container Escape in Hapi with Jwt Tokens
Container Escape in Hapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A container escape in a Hapi application that uses JWT tokens typically arises when token validation logic is coupled with unchecked host metadata or when runtime environment variables are exposed through API endpoints. Hapi applications often rely on JWT for stateless authentication, and if the implementation does not strictly validate token claims, an attacker may leverage manipulated tokens to access host-level information or endpoints that expose container internals.
Consider an endpoint that decodes a JWT and returns the decoded payload as part of a debug or introspection route. If the route is unauthenticated or improperly scoped, an unauthenticated attacker can submit a token with arbitrary claims, and the server may reflect sensitive environment details such as container IDs, mounted paths, or internal service names. This becomes a container escape vector when the exposed information aids in probing for lateral movement or host filesystem access.
Another scenario involves misconfigured CORS or route permissions where token validation is skipped for certain paths. An attacker can use a valid JWT obtained elsewhere to pivot into administrative routes that expose container runtime details. Because JWTs can carry metadata, failing to enforce strict claim checks (issuer, audience, expiration) may allow an attacker to forge tokens with elevated scopes and request endpoints that return container-specific data, effectively breaking the boundary between application and host.
In practice, the risk materializes when security checks such as Authentication, BOLA/IDOR, and Property Authorization are not rigorously applied to JWT-secured routes. middleBrick’s scans detect such gaps by correlating OpenAPI/Swagger definitions with runtime behavior, identifying endpoints that accept JWTs but do not enforce strict validation or isolation. This is especially relevant when tokens are used for debugging or introspection features that should never be exposed in production.
For example, an endpoint defined as /debug/payload that returns the full JWT payload without verifying scopes or audience may inadvertently disclose container identifiers present in custom claims. middleBrick flags these as high-risk findings under Authentication and Property Authorization checks, providing remediation guidance to tighten token validation and remove debug endpoints from public surfaces.
Jwt Tokens-Specific Remediation in Hapi — concrete code fixes
To remediate container escape risks tied to JWT usage in Hapi, enforce strict token validation, avoid exposing sensitive claims, and isolate debug or introspection routes. Below are concrete, secure coding patterns for Hapi using the hapi-auth-jwt2 plugin.
1. Configure JWT validation with strict claim checks
Ensure your JWT validation verifies issuer (iss), audience (aud), and expiration. Do not accept unsigned tokens or permissive validation.
const Hapi = require('@hapi/hapi');
const Jwt = require('@hapi/jwt');
const validate = async (decoded, request, h) => {
// Perform additional checks, e.g., verify token scopes or user status
if (!decoded.scopes || !decoded.scopes.includes('read:data')) {
return { isValid: false };
}
return { isValid: true, credentials: decoded };
};
const init = async () => {
const server = Hapi.server({ port: 4000, host: 'localhost' });
await server.register(Jwt);
server.auth.strategy('jwt', 'jwt', {
keys: process.env.JWT_SECRET || 'your-very-secure-secret-change-this',
validate: validate,
verifyOptions: {
issuer: 'myapp.com',
audience: 'myapp-audience',
algorithms: ['HS256']
}
});
server.defaultAuth = 'jwt';
server.route({
method: 'GET',
path: '/secure/data',
options: {
auth: 'jwt',
handler: (request, h) => {
// Safe: token validated with strict claims
return { message: 'Access granted', user: request.auth.credentials };
}
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
init();
2. Avoid exposing container or host details in responses
Never return raw JWT payloads or environment details on public endpoints. If you need introspection, protect the route tightly and redact sensitive claims.
server.route({
method: 'GET',
path: '/introspect',
options: {
auth: 'jwt',
handler: (request, h) => {
// Redact sensitive claims before returning
const { iat, exp, iss, ...safePayload } = request.auth.credentials;
return { introspection: safePayload };
}
}
});
3. Enforce route-level authorization and avoid public debug endpoints
Do not expose routes like /debug/payload in production. If needed for development, restrict by IP and require elevated scopes.
server.route({
method: 'GET',
path: '/debug/payload',
options: {
auth: {
strategies: ['jwt'],
scope: ['admin']
},
handler: (request, h) => {
// Only include non-sensitive metadata
return { scopes: request.auth.credentials.scopes };
}
}
});
4. Rotate secrets and validate key sources
Do not hardcode secrets. Use environment variables and ensure keys are rotated regularly. Validate the source of keys if using asymmetric algorithms.
const server = Hapi.server({ port: 4000 });
await server.register(Jwt);
server.auth.strategy('jwt', 'jwt', {
keys: process.env.JWT_PUBLIC_KEY ? { key: process.env.JWT_PUBLIC_KEY, verify: true } : 'fallback-invalid-key',
verifyOptions: {
algorithms: ['RS256']
}
});
By combining strict JWT validation, claim checks, and careful route design, you reduce the attack surface that could lead to container escape. middleBrick’s scans can highlight routes where JWT usage lacks these safeguards, guiding you toward more secure configurations.