HIGH injection flawssailsapi keys

Injection Flaws in Sails with Api Keys

Injection Flaws in Sails with Api Keys — how this specific combination creates or exposes the vulnerability

Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query. In Sails.js, combining injection-prone endpoints with the use of API keys can amplify risk by exposing both functionality and long-lived credentials. If an API endpoint in Sails dynamically builds queries using user-controlled parameters and also returns or logs API keys, an attacker may be able to inject malicious payloads that reveal keys or pivot to other backend systems.

For example, a Sails controller that concatenates user input into a raw database query could allow injection via parameters such as filter or search. If that same endpoint embeds API keys in JSON responses for downstream service authentication, an injection vulnerability can lead to key disclosure. Insecure direct object references (IDOR) or broken function-level authorization can intersect with injection: an attacker without permissions might exploit injection to access or modify data belonging to other users, including key material stored in models or configuration records.

SSRF and external injection are also relevant. A Sails service that accepts a URL from the client and uses API keys to authenticate outbound requests can be abused if the URL is user-supplied. An attacker could supply a malicious internal address, causing the server to send API keys to a controlled endpoint. Input validation failures and lack of allowlists for URLs or hostnames increase the likelihood of successful injection against API key handling logic.

Common real-world patterns include dynamic where clauses in Waterline ORM queries, usage of .sendNativeQuery with string interpolation, and constructing HTTP callbacks with keys pulled from models. These patterns become dangerous when user data influences query structure or headers without strict sanitization and when API keys are serialized into logs, error messages, or API responses. Proper schema design, strict input validation, and avoiding key exposure in responses are essential to reduce the attack surface.

Api Keys-Specific Remediation in Sails — concrete code fixes

Remediation focuses on preventing injection and ensuring API keys are never constructed, logged, or returned via user-influenced code paths. Below are concrete Sails examples that illustrate insecure patterns and their secure counterparts.

1. Avoid dynamic query building with user input

Instead of concatenating user input into Waterline ORM queries, use parameterized conditions and explicit schema validation.

// Insecure: dynamic query with user input
const userFilter = req.param('filter');
const records = await User.where({ name: userFilter });

// Secure: validate and sanitize input, use parameterized queries
const schema = Joi.object({
  filter: Joi.string().max(64).pattern(/^[a-zA-Z0-9_\-\s]+$/).required()
});
const { error, value } = schema.validate(req.all());
if (error) throw badRequest('Invalid input');
const records = await User.where({ name: value.filter });

2. Use parameterized native queries and avoid string interpolation

If native queries are required, use placeholders instead of injecting raw values.

// Insecure: string interpolation in native query
const sql = `SELECT * FROM user WHERE id = ${req.param('id')}`;
const users = await User.getDatastore().sendNativeQuery(sql);

// Secure: parameterized query with placeholders
const sql = 'SELECT * FROM user WHERE id = ?';
const users = await User.getDatastore().sendNativeQuery(sql, [req.param('id')]);

3. Never expose API keys in responses or logs

Strip or mask keys before serialization and avoid logging raw key values.

// Insecure: returning API key in JSON response
return res.ok({
  token: apiRecord.key,
  scopes: apiRecord.scopes
});

// Secure: return only necessary metadata, mask the key
return res.ok({
  token: apiRecord.key ? apiRecord.key.slice(0, 4) + '****' : null,
  scopes: apiRecord.scopes
});

4. Validate and restrict outbound URLs to prevent SSRF and injection

When making outbound HTTP requests with API keys, validate the target URL against an allowlist and avoid using user-controlled URLs directly.

// Insecure: using user-supplied URL with API key
const url = req.param('webhookUrl');
await sails.helpers.http.get(url, { Authorization: `Bearer ${apiKey}` });

// Secure: allowlist domains and use strict validation
const allowedDomains = ['https://api.example.com', 'https://webhook.partner.org'];
const url = req.param('webhookUrl');
if (!allowedDomains.some(d => url.startsWith(d))) {
  throw badRequest('Webhook URL not allowed');
}
await sails.helpers.http.get(url, { Authorization: `Bearer ${apiKey}` });

5. Enforce authorization before key access and use per-request tokens

Ensure that the requesting user is authorized to access or manage API keys, and prefer short-lived tokens over long-lived keys where feasible.

// Insecure: no ownership check before key usage
const key = await ApiKey.findOne(req.param('keyId'));
await ExternalService.call({ token: key.token });

// Secure: verify ownership and scope
const key = await ApiKey.findOne({ id: req.param('keyId'), userId: req.user.id });
if (!key) throw notFound();
await ExternalService.call({ token: key.token });

Frequently Asked Questions

How can input validation in Sails reduce injection risks involving API keys?
Use a strict validation library (e.g., Joi) to enforce allowlists on user input, avoid dynamic query construction, and ensure keys are never echoed back or used to directly build queries.
What practices help prevent API key exposure in Sails responses and logs?
Never serialize raw API keys into JSON responses, mask keys in logs, and implement strict authorization checks before any key access; prefer short-lived tokens and avoid returning keys to the client.