HIGH sql injectionfeathersjsjwt tokens

Sql Injection in Feathersjs with Jwt Tokens

Sql Injection in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability

SQL injection in a FeathersJS application using JWT tokens occurs when untrusted input is concatenated into SQL queries, even though authentication is enforced via a JWT. The presence of a valid JWT does not prevent SQL injection; it only confirms identity or permissions. If user-controlled data such as query parameters, headers, or request bodies are directly interpolated into SQL strings or passed to unsafe query builders, an attacker can manipulate the SQL logic. For example, an attacker authenticated with a legitimate JWT might supply a malicious query parameter like id=1 OR 1=1 that alters the meaning of a dynamically built query. FeathersJS services often rely on adapters (e.g., for Sequelize, TypeORM, or Knex), and if input validation is skipped or improperly configured, these adapters may forward raw input to the database. Because the scan tests unauthenticated attack surfaces, it can still detect injection points in endpoints that incorrectly trust JWT-authenticated contexts. Common patterns include using string concatenation or template literals to build queries, or dynamic query generation that incorporates user-supplied fields such as sort, filter, or select. The OWASP API Top 10 lists injection among the most critical API risks, and this combination highlights how authentication mechanisms alone do not mitigate injection flaws.

Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes

To remediate SQL injection in FeathersJS while using JWT tokens, ensure that all database interactions use parameterized queries or an ORM/query builder with built-in sanitization. Never directly interpolate user input into SQL strings, even when a JWT is present and verified. Apply strict input validation and schema checks using libraries such as Ajv, and configure FeathersJS hooks to sanitize and validate data before it reaches services. Below are concrete code examples illustrating secure practices.

Example 1: Using Knex with parameterized queries

const { authenticate } = require('@feathersjs/authentication');
const { express } = require('@feathersjs/express');
const knex = require('./knex-instance');

const app = express();
app.configure(authenticate());

app.use('/todos', {
  async find(params) {
    const { $select, $filter } = params.query;
    let query = knex('todos');

    if ($select) {
      // Validate $select against an allowed list to avoid column injection
      const allowedColumns = ['id', 'title', 'completed'];
      const columns = $select.split(',').filter(col => allowedColumns.includes(col.trim()));
      if (columns.length) query = query.select(columns);
    }

    if ($filter) {
      try {
        const filter = JSON.parse($filter);
        if (filter.status) {
          query = query.where('status', filter.status);
        }
      } catch (err) {
        throw new Error('Invalid filter JSON');
      }
    }

    return query;
  }
});

module.exports = app;

Example 2: Using TypeORM with repositories and parameterized methods

const { authenticate } = require('@feathersjs/authentication');
const { express } = require('@feathersjs/express');
const { TypeORM } = require('@feathersjs/typeorm');
const { Todo } = require('./models');

const app = express();
app.configure(authenticate());
app.configure(TypeORM({
  entities: [Todo],
  options: { type: 'postgres', /* ... */ }
}));

app.use('/todos', {
  async get(id, params) {
    const todoRepository = params.app.get('sequelize').models.Todo.repository;
    // Using parameterized query via repository
    const todo = await todoRepository.findOneBy({ id: Number(id) });
    if (!todo) {
      throw new Error('Not found');
    }
    return todo;
  }
});

module.exports = app;

Example 3: Validating and sanitizing input in a FeathersJS hook

const { iff, isProvider } = require('feathers-hooks-common');

const sanitizeAndValidate = context => {
  const { data } = context;
  if (data.id) {
    // Ensure id is a positive integer
    const id = Number(data.id);
    if (!Number.isInteger(id) || id <= 0) {
      throw new Error('Invalid id');
    }
    context.data.id = id;
  }
  return context;
};

module.exports = {
  before: {
    all: [iff(isProvider('external'), sanitizeAndValidate)],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
};

JWT-specific notes

  • Always verify the JWT using a strong secret or public key and validate claims such as exp and iss.
  • Do not rely on JWT scopes or roles alone to enforce data-level permissions; combine with explicit input validation and parameterized queries.
  • Ensure that JWTs are transmitted only over HTTPS and that tokens are not logged in a way that could expose sensitive data.

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

Does a valid JWT prevent SQL injection in FeathersJS?
No. Authentication via JWT does not protect against SQL injection. Injection occurs when untrusted input is improperly included in SQL queries. You must use parameterized queries, prepared statements, or an ORM/query builder with sanitization regardless of authentication.
Can middleBrick detect SQL injection in authenticated endpoints using JWTs?
Yes. middleBrick scans the unauthenticated attack surface and can identify endpoints vulnerable to SQL injection, including those that require JWTs, by analyzing input handling and query construction patterns.