Api Key Exposure in Hapi with Mongodb
Api Key Exposure in Hapi with Mongodb — how this specific combination creates or exposes the vulnerability
When an API built with Hapi interacts with a MongoDB backend, improper handling of API keys can lead to their unintended exposure. This typically occurs when API keys are passed in HTTP headers, stored in logs, or embedded into MongoDB documents without adequate protection. In Hapi, routes that accept keys via headers or query parameters may inadvertently write those keys into database records if request metadata is persisted for debugging, auditing, or correlation purposes.
For example, a developer might log incoming headers or attach the key to a request extension object that is later inserted into a MongoDB collection. If those logs or documents are accessible to unauthorized users or exposed through an insecure endpoint, the API key becomes a credential leak. This is especially risky when MongoDB collections are not properly restricted, allowing read access to collections that should contain only operational data.
Another vector involves environment variables used to configure the MongoDB connection string. If an API key is concatenated into the connection URI or stored alongside it in configuration files, and that configuration is exposed through source control or a misconfigured dashboard, the key can be extracted. Hapi applications that use plugins for request validation or transformation might also copy header values into response payloads during error handling, inadvertently returning the key to the client.
MongoDB’s flexible schema exacerbates the issue. Without strict schema enforcement, it is easy to store raw headers, including authorization tokens, directly into documents. If those documents are later queried by less-privileged services or exposed through an insecure GraphQL or REST layer, the keys can be harvested. Attackers often search for such patterns using automated scans, looking for collections containing fields named api_key, authorization, or x-api-key.
The combination of Hapi’s plugin-driven architecture and MongoDB’s document model increases the attack surface if developers do not explicitly sanitize inputs before persistence. Regular security scans using tools that test unauthenticated endpoints can detect whether API keys are being reflected in responses or stored in accessible database collections, helping teams identify these exposures before they are exploited.
Mongodb-Specific Remediation in Hapi — concrete code fixes
To prevent API key exposure in a Hapi application using MongoDB, implement strict input sanitization, avoid persisting sensitive headers, and enforce least-privilege access patterns. Below are concrete, working code examples that demonstrate secure practices.
1. Avoid storing API keys in MongoDB
Never insert raw headers containing API keys into MongoDB documents. Instead, hash or omit them entirely.
const Hapi = require('@hapi/hapi');
const { MongoClient } = require('mongodb');
const crypto = require('crypto');
const sanitizeApiKey = (key) => {
return crypto.createHash('sha256').update(key).digest('hex');
};
const init = async () => {
const server = Hapi.server({ port: 3000, host: 'localhost' });
server.route({
method: 'POST',
path: '/data',
options: {
handler: async (request, h) => {
const apiKey = request.headers['x-api-key'];
const mongoClient = new MongoClient('mongodb://localhost:27017');
await mongoClient.connect();
const db = mongoClient.db('secureDb');
// ✅ Store only a hash, never the raw key
await db.collection('requests').insertOne({
timestamp: new Date(),
endpoint: request.path,
apiKeyHash: sanitizeApiKey(apiKey)
});
await mongoClient.close();
return { status: 'ok' };
}
}
});
await server.start();
};
init();
2. Restrict MongoDB collection access
Ensure your MongoDB user has read/write access only to necessary collections and never full administrative privileges.
// Example MongoDB user creation with minimal privileges
use secureDb
db.createUser({
user: "hapiAppUser",
pwd: "StrongPassword123!",
roles: [
{ role: "readWrite", db: "secureDb", collection: "requests" }
// Do NOT grant dbAdmin or userAdmin roles to the app user
]
});
3. Validate and filter headers before use
Use Hapi’s validation schema to reject requests with unexpected or sensitive headers.
server.route({
method: 'POST',
path: '/submit',
options: {
validate: {
headers: Joi.object({
'x-api-key': Joi.string().required(),
'user-agent': Joi.string().optional(),
// Explicitly forbid forwarding sensitive headers
authorization: Joi.forbidden()
}).unknown(false) // Reject any unknown headers
},
handler: (request, h) => {
// Safe to use request.headers['x-api-key'] here
return { received: true };
}
}
});
4. Use environment variables for connection strings
Never hardcode connection URIs with embedded credentials. Use environment variables and ensure they are not logged.
const mongoUri = process.env.MONGODB_URI; // Set outside the codebase
const client = new MongoClient(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true
});
5. Audit and monitor stored data
Periodically review stored documents to ensure no sensitive fields exist. Use MongoDB’s schema validation to reject documents containing prohibited keys.
db.createCollection("requests", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["timestamp", "endpoint", "apiKeyHash"],
properties: {
timestamp: { bsonType: "date" },
endpoint: { bsonType: "string" },
apiKeyHash: { bsonType: "string", pattern: "^[a-f0-9]{64}$" }
// Reject any additional fields that might contain raw keys
},
additionalProperties: false
}
}
});Frequently Asked Questions
How can I detect if my Hapi API is accidentally exposing API keys in MongoDB?
api_key or authorization, and ensure no raw headers are being persisted.