HIGH sql injectionfeathersjsapi keys

Sql Injection in Feathersjs with Api Keys

Sql Injection in Feathersjs with Api Keys — how this specific combination creates or exposes the vulnerability

SQL Injection in a FeathersJS service becomes significantly more dangerous when API keys are used for authentication because keys often grant broad, service-level permissions. FeathersJS services typically rely on data adapters (e.g., feathers-sequelize, feathers-typeorm) that construct queries from user-supplied parameters. If input validation and query building are not strictly enforced, an attacker can inject malicious SQL through parameters that are processed by the adapter.

When API keys are involved, the risk pattern shifts from user-specific data exposure to potential lateral movement or privilege escalation across tenants or tables. For example, an API key with read access to a users table might be abused if a vulnerable query like SELECT * FROM users WHERE id = ${id} is constructed via string concatenation. An attacker could provide an id such as 1 OR 1=1, causing the query to return all rows. Because the request is authenticated with a valid API key, the server may treat the request as legitimate and expose data that should be restricted.

Another scenario involves multi-tenant setups where an API key maps to a specific organization. If a query filters by tenant ID using string interpolation instead of parameterized inputs, an attacker can bypass tenant isolation. A crafted payload such as '; DROP TABLE invoices; -- could be injected if input is not sanitized, leading to data loss or corruption. Even when using an ORM, misconfigured hooks or custom before hooks that modify query parameters can reintroduce SQL fragments from untrusted sources, enabling injection despite the presence of API key checks.

FeathersJS hooks that modify params.sequelize or directly alter the query object are common culprits. For instance, a hook that appends a where clause without validating or parameterizing values can merge attacker-controlled strings into the final SQL. Because API keys are often checked early in the authentication hook, the subsequent service logic may trust the identity context and skip further sanitization, inadvertently allowing injected SQL to execute with the permissions of the API key.

Real-world attack patterns include using SQL Injection to extract sensitive data via UNION-based techniques or to bypass authentication by manipulating WHERE clauses. In a FeathersJS application, an endpoint like /api/invoices that accepts a query parameter filter[where][id] could be exploited if the value is not properly escaped. With a valid API key, an attacker could submit filter[where][id]=1; SELECT * FROM users and, depending on the adapter and database driver, potentially observe unexpected results or errors that leak schema information.

The combination of FeathersJS flexibility and SQL databases requires rigorous input validation, strict use of parameterized queries, and least-privilege database permissions for API keys. Otherwise, authentication via API keys can provide a false sense of security while underlying query construction flaws enable unauthorized data access or manipulation.

Api Keys-Specific Remediation in Feathersjs — concrete code fixes

Remediation centers on ensuring that API key authentication does not inadvertently trust user input. Always treat data from query parameters, headers, and payloads as untrusted, even when a valid API key is present.

1. Use Parameterized Queries with Feathers-Sequelize

When using feathers-sequelize, rely on ORM-safe query structures instead of raw SQL or string concatenation.

// Safe: using parameterized where clause
app.service('invoices').find({
  query: {
    where: {
      id: req.query.id // ORM will parameterize this
    }
  }
});

// Avoid: raw query with concatenation
app.service('invoices').find({
  raw: true,
  query: 'SELECT * FROM invoices WHERE id = ' + req.query.id
});

2. Validate and Sanitize Input in Hooks

Add a before hook to validate and sanitize incoming data. Use libraries like joi or express-validator.

const { validator } = require('feathers-hooks-common');
const sanitize = require('validator').escape;

app.service('users').hooks({
  before: {
    create: [validator({
      id: ['isInt'],
      email: ['isEmail']
    })],
    update: [validator({
      id: ['isInt']
    })]
  }
});

3. Enforce Parameterized Filters in Custom Methods

If you expose custom methods that build queries, ensure they use parameterized inputs and avoid dynamic SQL fragments.

// Safe custom method
app.methods.myReport = async function(params) {
  const { orgId, dateRange } = params.query;
  // Use parameterized query building
  return params.sequelize.query(
    'SELECT * FROM reports WHERE org_id = :orgId AND date BETWEEN :start AND :end',
    { replacements: { orgId, start: dateRange.start, end: dateRange.end }, type: params.sequelize.QueryTypes.SELECT }
  );
};

4. Apply Least-Privilege Database Permissions

Configure database roles so API keys used by Feathers services have only necessary permissions (e.g., SELECT/INSERT on specific tables, no DROP or ALTER). This limits the impact of any potential injection.

5. Disable Raw Query Exposure in Services

Avoid enabling raw: true or exposing endpoints that accept raw SQL fragments. If necessary, strictly whitelist allowed query fields and use parameterized inputs.

Example Secure Service Setup

const app = require('@feathersjs/feathers')();
const sequelize = require('./sequelize-client');

app.configure(require('@feathersjs/express').rest());
app.configure(require('@feathersjs/socketio'));

app.use('/secure-data', require('./services/data-service'));

app.service('secure-data').hooks({
  before: {
    all: [
      async context => {
        // Ensure API key validated earlier; now enforce strict query shape
        if (context.params.query && context.params.query.filter) {
          // Reject unexpected operators or raw expressions
          const allowedFields = ['id', 'orgId', 'status'];
          const where = context.params.query.filter.where || {};
          for (const key of Object.keys(where)) {
            if (!allowedFields.includes(key)) {
              throw new Error('Invalid filter field');
            }
          }
        }
        return context;
      }
    ]
  }
});

These steps ensure that API key authentication remains a boundary for identity verification rather than a vector for SQL Injection in FeathersJS applications.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can API key authentication alone prevent SQL Injection in FeathersJS?
No. API key authentication verifies identity but does not protect against malicious input. SQL Injection must be prevented through parameterized queries, input validation, and safe query construction regardless of authentication.
How does middleBrick help detect SQL Injection risks in FeathersJS APIs?
middleBrick scans unauthenticated attack surfaces and includes checks for injection-prone patterns. By correlating OpenAPI specs with runtime behavior, it can flag endpoints where user input may reach SQL construction without proper parameterization, even when API keys are used for access control.