Api Key Exposure in Sails with Mongodb
Api Key Exposure in Sails with Mongodb — how this specific combination creates or exposes the vulnerability
When a Sails application connects to a MongoDB backend, improper handling of API keys can expose sensitive credentials through the application’s API surface. Sails, an MVC framework for Node.js, often interacts with MongoDB via an ORM-like layer such as Waterline. If API keys or database credentials are stored in configuration files or environment variables and then inadvertently exposed through controller actions or logs, they can be extracted by an attacker leveraging common insecure deserialization, excessive data exposure, or unsafe consumption patterns.
In this stack, API keys may be exposed when Sails controllers directly return internal configuration objects or database connection details in API responses, for example via debug endpoints or error messages. MongoDB connection strings typically contain credentials; if a Sails controller or service passes these strings directly to the client or logs them without masking, an attacker conducting black-box scanning can detect these leaks through response content analysis or log inspection.
Additionally, if the Sails application uses unauthenticated endpoints that query MongoDB and return raw database metadata or sample documents, an attacker can infer the presence of embedded API keys or tokens within documents. This is especially risky when data exposure checks are not enforced, as sensitive fields may be returned alongside public data. The combination of Sails’ rapid scaffolding and MongoDB’s flexible document model increases the likelihood of accidentally exposing keys if schema validation and field-level authorization are not explicitly enforced.
Common attack patterns include probing endpoints for verbose error messages that stack trace database connection details, or using SSRF techniques to make the server connect to internal MongoDB instances and return configuration snippets. Without proper input validation and output filtering, the API becomes a conduit for credential leakage.
Mongodb-Specific Remediation in Sails — concrete code fixes
To prevent API key exposure when using MongoDB with Sails, implement strict separation between internal configuration and API responses, and sanitize all data returned from database queries. Below are concrete code examples demonstrating secure practices.
1. Exclude sensitive fields from API responses
Ensure that sensitive fields such as password, apiKey, or connectionString are never included in JSON responses. Use Sails’ toJSON and toObject hooks to redact sensitive data at the model level.
// api/models/User.js
module.exports = {
attributes: {
email: { type: 'string', required: true },
password: { type: 'string', minLength: 8 },
apiKey: { type: 'string' },
// Ensure sensitive fields are omitted from JSON output
toJSON: function() {
const obj = this.toObject();
delete obj.password;
delete obj.apiKey;
return obj;
},
toJSON: function() {
const obj = this.toObject();
delete obj.password;
delete obj.apiKey;
return obj;
}
}
};
2. Use environment variables with runtime masking
Store MongoDB connection strings and API keys in environment variables and access them securely within Sails configuration. Avoid logging these values, and ensure that configuration loading does not expose them through debug endpoints.
// config/datastores.js
module.exports.datastores = {
default: {
adapter: 'sails-mongo',
url: process.env.MONGODB_URI, // e.g., mongodb+srv://user:[email protected]/db
database: process.env.MONGODB_DB,
}
};
In production, ensure that process.env.MONGODB_URI is injected securely via your hosting platform or secrets manager, and that application logs are configured to mask values containing mongodb+srv:// or apiKey=.
3. Implement field-level authorization in controllers
Do not return entire MongoDB documents from controller actions. Instead, explicitly select safe fields and validate ownership to prevent Insecure Direct Object Reference (IDOR) and BOLA issues that could lead to key exposure.
// api/controllers/ProfileController.js
module.exports = {
me: async function (req, res) {
if (!req.user) return res.unauthorized();
const user = await User.findOne(req.user.id);
if (!user) return res.notFound();
// Return only safe, non-sensitive fields
return res.ok({
id: user.id,
email: user.email,
name: user.name,
role: user.role
});
}
};
4. Validate and sanitize query parameters
Prevent injection and over-fetching by validating query parameters before using them in MongoDB queries. Use Waterline’s built-in validation and avoid passing raw user input directly to find or where clauses.
// api/controllers/SearchController.js
module.exports = {
search: async function (req, res) {
const query = req.query.q;
if (!query || query.length > 100) {
return res.badRequest('Invalid query parameter');
}
// Safe usage: parameterized query
const results = await User.find({
where: {
email: { contains: query }
},
select: ['id', 'email', 'name'] // Explicit field selection
});
return res.ok(results);
}
};
5. Disable debug and introspection endpoints
Ensure that Sails’ blueprint APIs and any custom debug routes are disabled in production. Remove or protect endpoints that might return model schemas or internal configuration, which could aid an attacker in locating API keys.
// config/blueprints.js
module.exports.blueprints = {
actions: false,
rest: false,
shortcuts: false,
populate: false
};