Api Key Exposure in Hapi with Redis
Api Key Exposure in Hapi with Redis — how this specific combination creates or exposes the vulnerability
Hapi is a rich framework for building HTTP services in Node.js, and it is commonly used with Redis as a distributed cache or session store. When API keys are handled in Hapi and stored or logged alongside Redis operations, the combination can unintentionally expose those keys through logs, error messages, or misconfigured cache entries.
In a typical Hapi route, an API key may be read from request headers, validated, and then passed to a Redis client to retrieve or store data. If the key is included in cache keys, used as a Redis field value, or echoed in debug output, it can be exposed to anyone who can access logs or error traces. For example, logging the full Redis command arguments without redaction may print the key in plaintext to console or log aggregation systems.
Another exposure path involves error handling. When a Redis operation fails and the error object is serialized into an HTTP response or log, the key may be embedded in the message if the application includes request metadata in error context. This is common when developers attach the entire request headers or query parameters to error reports for debugging purposes.
Additionally, if the API key is used as a Redis key prefix (e.g., apikey:{key}:data) without proper access controls, anyone who can enumerate keys or access the cache may infer relationships or retrieve sensitive data. Even if Redis is not directly exposed externally, misconfigured network rules or shared development environments can allow unintended access to these keys.
The risk is compounded when the same Redis instance is used for multiple environments or tenants, as keys from different services may collide or be readable by unintended services. MiddleBrick checks for such risky patterns during unauthenticated scans, looking for indicators like keys transmitted in error contexts or logged without redaction.
Redis-Specific Remediation in Hapi — concrete code fixes
To prevent API key exposure when using Hapi with Redis, apply strict input handling, avoid logging sensitive values, and structure Redis keys and data so that keys are never stored or transmitted in clear text where they can be exposed.
1. Avoid logging or serializing API keys
Ensure that API keys are never included in log messages, error objects, or debug output. Use redaction when logging request metadata.
// Good: redact the API key before logging
const redactedHeaders = { ...request.headers };
delete redactedHeaders['api-key'];
server.log(['info'], { route: request.route.path, headers: redactedHeaders });
2. Do not use API keys directly as Redis keys or values
Instead of storing raw keys as Redis keys or values, use indirect references or hashes. If you must store sensitive data, use Redis hashes and limit field exposure.
// Good: use a mapping key and store minimal sensitive data
const crypto = require('crypto');
const keyHash = crypto.createHash('sha256').update(request.headers['api-key']).digest('hex');
await redisClient.hSet(`api:session:${keyHash}`, 'userId', userId);
await redisClient.expire(`api:session:${keyHash}`, 3600);
3. Separate cache keys from sensitive values
Keep API keys out of cache key construction. If you need to associate data with a key, use a non-sensitive identifier derived from the key rather than the key itself.
// Good: derive a non-sensitive key identifier
const keyId = crypto.createHash('sha256').update(request.headers['api-key']).digest('base64url');
const cached = await redisClient.get(`cache:resource:${keyId}`);
if (cached) {
return JSON.parse(cached);
}
4. Sanitize Redis errors before returning or logging
Do not propagate raw Redis errors that may include request context. Wrap errors and remove sensitive fields before logging or sending responses.
// Good: sanitize Redis errors
server.ext('onPreResponse', (request, h) => {
const response = request.response;
if (response.isBoom && response.output.payload) {
// Remove any internal fields that might contain key material
delete response.output.payload.meta;
}
return response;
});
5. Use environment-based Redis configuration and ACLs
Configure separate Redis database indices or ACL rules per environment. Ensure that the Hapi Redis client is instantiated with least-privilege credentials and that connection parameters are injected securely.
// Good: configure Redis client with limited permissions
const redisClient = require('redis').createClient({
url: process.env.REDIS_URL,
password: process.env.REDIS_PASSWORD,
tls: {},
legacyMode: false,
});
redisClient.on('error', (err) => console.error('Redis client error:', err.message));