HIGH injection flawsfeathersjs

Injection Flaws in Feathersjs

How Injection Flaws Manifests in Feathersjs

Injection flaws in Feathersjs applications occur when untrusted data is sent to an interpreter as part of a command or query. Feathersjs, built on Express and using services for data operations, creates several injection vectors that developers must understand.

The most common injection pattern in Feathersjs involves service method parameters. Consider this vulnerable code:

const { params } = context;
const query = await app.service('users').find({
query: { email: params.query.email }
});

This allows NoSQL injection because Feathersjs passes the query object directly to the database adapter. An attacker could send { "email": { "$ne": null }" } to bypass authentication or extract data.

Another Feathers-specific injection vector is in service hooks. Hooks can execute arbitrary code if they improperly handle user input:

async function validateEmail(context) {
const { email } = context.data;
if (email.includes('example.com')) {
throw new Error('Invalid domain');
}
return context;
}

While this hook itself isn't injectable, if it dynamically constructs queries or uses eval() on user input, injection becomes possible.

Feathersjs's real-time features through Socket.io create additional injection surfaces. WebSocket messages that aren't properly validated can trigger service methods with malicious parameters:

app.on('connection', (connection, auth) => {
connection.on('users.find', async (params) => {
const users = await app.service('users').find({
query: params.query
});
connection.emit('users.find', users);
});
});

Here, any client can send arbitrary query parameters over the WebSocket connection, potentially accessing data they shouldn't see.

Template injection is another concern when Feathersjs applications render views. If user input is inserted into templates without proper escaping:

app.get('/profile/:id', async (req, res) => {
const user = await app.service('users').get(req.params.id);
res.render('profile', { user });

An attacker could craft a username containing template syntax that gets executed when rendered.

Command injection can occur when Feathersjs applications execute system commands based on user input:

app.post('/import', async (req, res) => {
const { filename } = req.body;
const result = await exec(`mongoimport --file ${filename}`);
res.json({ result });
});

This allows an attacker to append additional commands by manipulating the filename parameter.

Feathersjs-Specific Detection

Detecting injection flaws in Feathersjs applications requires examining both the application code and runtime behavior. Static analysis can identify vulnerable patterns, but dynamic scanning reveals actual exploitation paths.

middleBrick's black-box scanning approach is particularly effective for Feathersjs applications. The scanner sends crafted payloads to API endpoints and observes responses, detecting injection attempts without requiring source code access.

For NoSQL injection detection in Feathersjs, middleBrick tests common MongoDB operators like $where, $regex, and $ne in query parameters. A typical test sends:

{
"email": { "$where": "this.email.length == 1" }
}

If the application returns different results than expected, it indicates potential injection vulnerability.

middleBrick's scanning process for Feathersjs applications includes:

  • Service endpoint discovery through OPTIONS requests
  • Parameter fuzzing with injection payloads
  • Response analysis for error patterns indicating injection
  • Authentication bypass attempts using injection in auth parameters
  • Authorization bypass testing through crafted queries

The scanner also detects injection in WebSocket endpoints by establishing Socket.io connections and sending malicious messages to registered event handlers.

For template injection, middleBrick looks for endpoints that accept user input and render it in responses. It injects template syntax and checks if it gets executed:

app.get('/search', async (req, res) => {
const { q } = req.query;
res.render('results', { query: q });
});

middleBrick would test this with payloads like {{7*7}} or ${7*7} to see if template evaluation occurs.

Command injection detection involves sending payloads that attempt to execute additional commands:

filename = "data.json; ls /"

The scanner monitors process execution and file system access patterns to identify successful command injection.

middleBrick's LLM security features are particularly relevant for Feathersjs applications using AI/ML integrations. The scanner tests for prompt injection in AI endpoints:

app.post('/chat', async (req, res) => {
const { message } = req.body;
const response = await chatModel(message);
res.json({ response });
});

middleBrick injects adversarial prompts to test if the model can be manipulated or if sensitive data leaks through the AI interface.

Feathersjs-Specific Remediation

Remediating injection flaws in Feathersjs requires a defense-in-depth approach. Start with input validation using Feathers's built-in hooks system:

const { hooks } = require('@feathersjs/hooks');

const validateInput = hooks(() => async (context, next) => {
const { email } = context.data;
if (!email || typeof email !== 'string') {
throw new Error('Invalid email format');
}
// Reject NoSQL operators
if (email.includes('$')) {
throw new Error('Invalid characters in email');
}
await next();
});

Apply this hook to services that handle user input:

app.service('users').hooks({
before: {
create: [validateInput],
update: [validateInput],
patch: [validateInput]
}
});

For query parameter validation, use Feathers's query validation hooks:

const { disallow, validateQuery } = require('feathers-hooks-common');

const safeQuery = validateQuery({
email: 'string?',
}, {
$ignore: true,
$remove: true
});

This ensures only expected query parameters are processed and rejects NoSQL operators.

For WebSocket injection prevention, validate all incoming messages:

app.on('connection', (connection, auth) => {
connection.on('users.find', async (params) => {
// Validate params before use
if (!params || typeof params !== 'object') {
connection.emit('error', 'Invalid parameters');
return;
}
const safeParams = sanitizeQuery(params);
const users = await app.service('users').find({
query: safeParams
});
connection.emit('users.find', users);
});
});

Command injection requires strict input sanitization. Never use string concatenation for command execution:

const { execFile } = require('child_process');

app.post('/import', async (req, res) => {
const { filename } = req.body;
if (!filename.endsWith('.json')) {
return res.status(400).json({ error: 'Invalid file format' });
}
// Use absolute path and whitelist allowed files
const safePath = path.join(__dirname, 'imports', filename);
return res.status(400).json({ error: 'Invalid file path' });
}
execFile('mongoimport', ['--file', safePath], (error, stdout) => {
if (error) return res.status(500).json({ error: error.message });
res.json({ result: stdout });
});
});

For template injection, use Feathers's view engine with auto-escaping enabled:

app.set('view engine', 'pug');
app.enable('view cache');

// In templates, always escape user input
p=user.name // Auto-escaped in Pug

Implement parameterized queries for database operations instead of dynamic query construction:

const sanitizeQuery = (query) => {
const sanitized = { ...query };
// Remove any NoSQL operators
Object.keys(sanitized).forEach(key => {
if (key.startsWith('$')) {
delete sanitized[key];
}
});
return sanitized;
};

For Feathersjs applications using external APIs or services, implement strict input validation and use HTTPS with certificate pinning:

const https = require('https');

const safeRequest = (url, options) => {
return new Promise((resolve, reject) => {
const sanitizedUrl = new URL(url);
// Validate host against whitelist
if (!allowedHosts.includes(sanitizedUrl.hostname)) {
return reject(new Error('Invalid host'));
}
https.get(sanitizedUrl, options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
};

Finally, implement comprehensive logging and monitoring to detect injection attempts:

const logger = require('winston');

app.use('/api', (req, res, next) => {
logger.info(`${req.method} ${req.path}`, {
ip: req.ip,
userAgent: req.get('User-Agent')
});
next();
});

Frequently Asked Questions

How does Feathersjs's service architecture make it vulnerable to injection attacks?
Feathersjs's service architecture abstracts database operations through a unified interface, which can inadvertently pass malicious query parameters directly to the database adapter. When services accept dynamic query objects without validation, attackers can inject NoSQL operators like $where, $regex, or $ne to manipulate database queries. The framework's flexibility in handling query parameters and hooks means that improperly sanitized input can flow through multiple layers before reaching the database, creating multiple injection points throughout the application stack.
Can middleBrick detect injection flaws in Feathersjs WebSocket endpoints?
Yes, middleBrick actively tests WebSocket endpoints by establishing Socket.io connections and sending malicious messages to registered event handlers. The scanner identifies real-time API endpoints through service discovery, then injects payloads targeting common injection patterns like NoSQL operators, command injection attempts, and template syntax. middleBrick analyzes the responses to determine if the injection was successful, providing specific findings about which WebSocket endpoints are vulnerable and what types of injection attacks succeeded.