Data Exposure in Hapi with Api Keys
Data Exposure in Hapi with Api Keys — how this specific combination creates or exposes the vulnerability
The Data Exposure check in middleBrick examines how APIs handle sensitive information at rest and in transit. When Api Keys are used for authentication in a Hapi application, several patterns can inadvertently expose those keys or the data they protect. A common scenario is logging request details, including headers, where the Authorization header carrying the Api Key is captured in application or access logs. If logs are centralized or retained for debugging, an attacker who gains access to the logs can harvest valid Api Keys and use them to impersonate clients or escalate access.
Another exposure path arises from improper error handling in Hapi. When routes protected by Api Key validation throw unhandled exceptions or return verbose stack traces, the responses may include details about the validation logic, the expected header format, or even partial key values if the key is inadvertently reflected in messages. For example, a route that validates req.headers['x-api-key'] and responds with a generic error may still include the header name in the response payload, giving an attacker confirmation that Api Key authentication is in use and how it is named.
Server-side template rendering or JSON serialization in Hapi can also contribute to Data Exposure. If Api Key values are accidentally included in JSON responses, HTML attributes, or query strings due to misconfigured serializers or caching layers, the keys may be exposed to unauthorized parties through browser history, network sniffing (when not using TLS), or compromised client-side code. middleBrick’s Data Exposure check looks for such reflection by analyzing the unauthenticated attack surface and correlating runtime observations with the OpenAPI specification to identify endpoints where sensitive data might be returned inappropriately.
Transport security is a related concern. Even when Api Keys are transmitted correctly, if the Hapi server does not enforce HTTPS or if TLS is misconfigured (e.g., weak ciphers, expired certificates), keys can be intercepted in transit. middleBrick’s Encryption check complements Data Exposure by verifying that endpoints are served over TLS and that responses do not contain sensitive data in plaintext where they could be cached or stored inadvertently by intermediaries.
Finally, the Inventory Management and Unsafe Consumption checks consider how Api Keys are stored and referenced within the application. Hard-coded keys in route files or configuration templates that are checked into version control can be extracted from repository history or build artifacts. middleBrick scans for indicators of such unsafe patterns during the black-box test, correlating findings with the spec to highlight endpoints where key exposure risk is elevated due to implementation practices in the Hapi server.
Api Keys-Specific Remediation in Hapi — concrete code fixes
To reduce Data Exposure risks when using Api Keys in Hapi, apply targeted code changes that minimize logging, enforce strict validation, and protect key transmission. Below are concrete, realistic examples you can adopt in your Hapi project.
1. Avoid logging sensitive headers
Ensure your Hapi server does not log the Authorization or x-api-key headers. Configure your logging strategy to redact sensitive headers.
// server.js
const Hapi = require('@hapi/hapi');
const init = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost',
routes: {
cors: {
origin: ['https://app.example.com'],
additionalHeaders: ['x-api-key']
}
}
});
// Example of safe logging that redacts sensitive headers
server.ext('onRequest', (req, h) => {
const logHeaders = { ...req.headers };
if (logHeaders['x-api-key']) {
logHeaders['x-api-key'] = 'REDACTED';
}
console.log('Incoming request:', {
method: req.method,
url: req.url,
headers: logHeaders
});
return h.continue;
});
server.route({
method: 'GET',
path: '/data',
options: {
handler: (request, h) => {
const apiKey = request.headers['x-api-key'];
if (apiKey !== process.env.API_KEY) {
return { error: 'Unauthorized' };
}
return { message: 'secure data' };
},
validate: {
headers: {
x-api-key: Joi.string().required()
}
}
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
init();
2. Use environment variables and avoid key reflection in responses
Never echo the Api Key back to the client. Validate against a stored key and return generic error messages.
// validate-key.js
const ApiKeyValidator = {
validate: (key) => {
return key === process.env.API_KEY;
}
};
module.exports = ApiKeyValidator;
// route handler using the validator
const Hapi = require('@hapi/hapi');
const ApiKeyValidator = require('./validate-key');
const registerRoutes = (server) => {
server.route({
method: 'POST',
path: '/secure-action',
options: {
handler: (request, h) => {
const providedKey = request.headers['x-api-key'];
if (!ApiKeyValidator.validate(providedKey)) {
// Do not reveal which part was incorrect
return { error: 'Unauthorized' };
}
return { status: 'ok' };
},
validate: {
headers: {
'x-api-key': Joi.string().required()
}
},
// Ensure errors do not leak key details
failAction: (request, h, error) => {
return h.response({ error: 'Unauthorized' }).code(401);
}
}
});
};
const init = async () => {
const server = Hapi.server({ port: 3000 });
registerRoutes(server);
await server.start();
console.log('Server running');
};
init();
3. Enforce HTTPS and secure transmission
Serve all endpoints over TLS and require Api Keys only over HTTPS. Use Hapi’s connection configuration to enforce secure practices.
// secure-server.js
const Hapi = require('@hapi/hapi');
const tls = require('tls');
const init = async () => {
const server = Hapi.server({
port: 443,
host: 'api.example.com',
tls: {
key: fs.readFileSync('/path/to/private.key'),
cert: fs.readFileSync('/path/to/cert.pem')
}
});
server.route({
method: 'GET',
path: '/health',
options: {
handler: () => ({ status: 'ok' }),
validate: {
headers: {
'x-api-key': Joi.string().required()
}
}
}
});
await server.start();
console.log('Secure server running on https://%s:%s', server.info.host, server.info.port);
};
init();
4. Rotate keys and audit usage
Implement a routine to rotate Api Keys and audit access patterns. While this is more operational than code, ensure your Hapi application can reload keys without restart and log key identifiers (not the keys themselves) for audit trails.
// key-rotation.js
let currentKey = process.env.API_KEY;
const checkKey = (key) => {
return key === currentKey;
};
// Periodically refresh key from secure source
setInterval(() => {
currentKey = process.env.ROTATED_API_KEY;
}, 3600000);
module.exports = { checkKey };
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 |