Data Exposure in Hapi with Basic Auth
Data Exposure in Hapi with Basic Auth — how this specific combination creates or exposes the vulnerability
The combination of Hapi’s default behaviors and Basic Authentication can unintentionally expose sensitive data when transport protections are absent or when debugging/logging settings reveal credentials or application internals. Basic Authentication sends credentials in an Authorization header encoded as Base64, which is trivial to decode if intercepted. Without TLS, credentials and any data returned by the endpoint are transmitted in clear text across the network, enabling passive sniffing and session hijacking.
Even when TLS is enabled, implementation issues can lead to data exposure. For example, Hapi servers that log request or response details may inadvertently record Authorization headers or sensitive payloads if logging is not carefully scoped. Hapi’s built-in validation and error reporting can also surface raw input and server details in error responses, giving an attacker information about data structures, user identifiers, or backend behavior. These error messages may include stack traces, database field names, or object representations that should never reach untrusted clients.
Another vector specific to Hapi involves route configuration and caching. If responses containing sensitive data are cached by intermediary proxies or the server’s own cache mechanisms without appropriate controls, and if those caches are improperly segmented or purged, data can be read by unintended users. Hapi’s route options, such as cache settings, must be explicitly configured to avoid storing sensitive information. Similarly, CORS misconfigurations can allow unauthorized origins to read responses that include sensitive data, especially when credentials are handled via headers and the server defaults to overly permissive rules.
The scanner’s checks for Data Exposure analyze whether endpoints return sensitive information such as personally identifiable information (PII), authentication tokens, or internal identifiers without protective mechanisms like masking or encryption. In a Hapi service using Basic Auth, the scanner inspects response payloads, headers, and error messages for patterns that match known sensitive data formats and flags endpoints where such exposure occurs. It also evaluates whether TLS is enforced and whether server-side logging or instrumentation might leak credentials or data in logs or metrics.
These findings map to real-world attack patterns and compliance considerations. For example, improper error handling in Hapi can contribute to information disclosure as described in parts of the OWASP API Security Top 10, and unencrypted transmission of credentials aligns with risks around insecure transport. A concrete example of risky code is a Hapi server that responds with full validation error objects containing user input, which may reveal whether a given username exists or expose internal field names.
Basic Auth-Specific Remediation in Hapi — concrete code fixes
To mitigate data exposure when using Basic Authentication in Hapi, enforce TLS, avoid logging sensitive headers, and structure error responses to minimize information leakage. Below are concrete, working examples that demonstrate secure configurations and practices.
1. Enforce TLS and use the h2 module for secure communication
Always serve your Hapi application over HTTPS. Use the h2 module to enforce TLS and require secure communication before any route logic executes.
const Hapi = require('@hapi/hapi');
const tls = require('tls');
const init = async () => {
const server = Hapi.server({
port: 443,
host: '0.0.0.0',
tls: {
key: fs.readFileSync('/path/to/server.key'),
cert: fs.readFileSync('/path/to/server.crt'),
rejectUnauthorized: true
}
});
server.auth.scheme('custombasic', (server) => {
return {
authenticate(request, h) {
const credentials = request.auth.credentials;
if (!credentials || credentials.user !== 'secureuser') {
return h.response({ message: 'Unauthorized' }).code(401);
}
return credentials;
}
};
});
server.auth.strategy('simple', 'custombasic');
server.route({
method: 'GET',
path: '/secure',
options: {
auth: 'simple',
plugins: {
// Avoid logging sensitive headers
logs: { collect: false }
}
},
handler: (request, h) => {
return { data: 'This is protected and only for authenticated, TLS-secured clients.' };
}
});
await server.start();
console.log('Server running securely with TLS and Basic Auth');
};
init();
2. Avoid logging Authorization headers or sensitive payloads
Configure your Hapi server and logging plugins to exclude Authorization headers and request/response bodies from logs. With the good-behavior logging approach, you reduce the risk of credentials or PII being persisted inadvertently.
const Hapi = require('@hapi/hapi');
const goodBehavior = require('good');
const server = Hapi.server({
port: 4000,
host: 'localhost'
});
await server.register({
plugin: goodBehavior,
options: {
reporters: {
console: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ log: '*', response: '*' }]
}, {
module: 'good-console'
}, 'stdout']
}
}
});
// Ensure sensitive headers are not included in logs
server.ext('onPreResponse', (request, h) => {
const response = request.response;
if (response && response.headers) {
// Example: strip or avoid exposing sensitive headers in any custom logging
// Actual header removal should be done at proxy/load balancer if needed
}
return h.continue;
});
server.route({
method: 'POST',
path: '/login',
options: {
auth: false,
plugins: {
// Configure logging to exclude Authorization
good: {
logFilters: {
excludeHeaders: ['authorization', 'cookie']
}
}
}
},
handler: (request, h) => {
const { username, password } = request.payload;
// Validate credentials and issue response without echoing raw Authorization
if (username === 'admin' && password === 'correct') {
return { message: 'Login successful' };
}
return { message: 'Invalid credentials' };
}
});
3. Return safe error messages and avoid data leakage
Customize Hapi’s error responses to avoid exposing stack traces, validation details, or data structure information. Use generic messages and ensure that errors do not include raw user input or internal identifiers.
const Hapi = require('@hapi/hapi');
const server = Hapi.server({
port: 5000,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/profile',
options: {
auth: false,
handler: (request, h) => {
// Simulate a condition where data might be missing
const user = null;
if (!user) {
// Return a generic error that does not reveal internal details
const error = new Error('Resource not found');
error.show = false; // Prevent Hapi from showing internal details in debug mode
return h.response({ message: 'Not found' }).code(404);
}
// Return safe, masked data only when appropriate
return { id: user.id, name: user.name };
}
}
});
server.ext('onPreResponse', (request, h) => {
const response = request.response;
if (response && response.isBoom) {
// Avoid leaking stack traces or internal error details
response.output.payload.show = false;
response.output.payload.message = 'An error occurred';
}
return h.continue;
});
server.start();
4. Configure route caching and CORS carefully
Explicitly control caching for sensitive endpoints and apply restrictive CORS settings to prevent unintended data reads. Do not rely on defaults when handling authenticated responses that may include private data.
const Hapi = require('@hapi/hapi');
const server = Hapi.server({
port: 6000,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/sensitive',
options: {
auth: false,
cache: {
// Explicitly disable caching or set short, private-only policies
privacy: 'private',
expiresIn: 1000 * 60 // 1 minute if caching is necessary
},
cors: {
origin: ['https://trusted.example.com'],
additionalHeaders: ['authorization'],
credentials: true
},
handler: (request, h) => {
return { note: 'Sensitive data should only be served to authorized, same-origin clients' };
}
}
});
server.start();
These remediation steps reduce the likelihood of data exposure by ensuring that credentials are not transmitted or logged in the clear, that errors do not disclose internal details, and that caching and CORS do not inadvertently expose sensitive responses.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |