Email Injection in Feathersjs with Api Keys
Email Injection in Feathersjs with Api Keys — how this specific combination creates or exposes the vulnerability
Email Injection in FeathersJS occurs when user-controlled input is concatenated into email headers or message bodies without validation or sanitization. This becomes particularly relevant when API access is controlled via Api Keys, because developers may assume that key-based authentication alone limits risk. In FeathersJS, services typically accept payloads that include fields such as to, from, or message when sending emails through integrations like SMTP or email APIs. If these fields are directly interpolated into headers or templates, an attacker can inject additional headers (e.g., CC, BCC, or Reply-To) or newline characters to alter the routing of the email.
When Api Keys are used, the API endpoint may expose an unauthenticated or weakly scoped route that accepts email-sending requests. Because middleBrick scans unauthenticated attack surfaces by default, it can detect whether email-sending endpoints are reachable via Api Key parameters that are improperly validated. Attackers can exploit this by injecting newline sequences (e.g., %0D%0A or \r\n) into header fields, leading to header manipulation or cross-protocol injection. For example, a crafted payload could append a second To: header or inject a Bcc: header to silently copy the email to an attacker-controlled address.
Real-world attack patterns include using CRLF injection to bypass intended recipients, which may expose internal communications or trigger phishing campaigns from a trusted domain. This maps to the OWASP API Top 10 category 'Broken Object Level Authorization' and can be detected by middleBrick’s BOLA/IDOR and Input Validation checks. The scanner tests whether newline characters in email fields lead to unexpected header splits, and whether Api Key–protected endpoints allow unauthenticated invocation of the email-sending service.
Because FeathersJS often relies on hooks and external transports like nodemailer, improperly sanitized input can propagate into SMTP transactions. middleBrick’s Email Injection checks validate that user-supplied data is escaped or whitelisted before being passed to transport layers. The tool also cross-references OpenAPI specs, so if your email-sending route is defined with parameters such as email.to or email.subject
In summary, the combination of FeathersJS email services and Api Keys does not inherently secure the system; if input validation is weak, Api Keys can become a vector for abuse where endpoints accept maliciously crafted email headers. middleBrick detects these issues by running active probes and spec–runtime correlation without requiring credentials, ensuring that injection risks are surfaced regardless of authentication assumptions.
Api Keys-Specific Remediation in Feathersjs — concrete code fixes
To remediate Email Injection in FeathersJS when using Api Keys, ensure that all email-related input is validated, sanitized, and strictly scoped. Avoid directly inserting user input into email headers. Instead, use a dedicated library or framework utilities to construct headers safely. Below are concrete code examples demonstrating secure patterns.
// src/services/email-notification/service.js
const { Service } = require('feathersjs');
const nodemailer = require('nodemailer');
class EmailNotificationService extends Service {
async create(data, params) {
const { apiKey } = params.query || {};
// Validate Api Key before proceeding (example validation)
if (!apiKey || !isValidApiKey(apiKey)) {
throw new Error('Invalid API Key');
}
const { to, subject, text } = data;
// Strict validation: allow only alphanumeric and limited special chars in email
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(to)) {
throw new Error('Invalid recipient email');
}
// Sanitize subject: remove newlines and control characters
const sanitizedSubject = subject.replace(/[\r\n]+/g, ' ').substring(0, 255);
// Sanitize text body if needed
const sanitizedText = text ? text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') : '';
// Use nodemailer with secure header construction
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT, 10) || 587,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
const mailOptions = {
from: process.env.EMAIL_FROM,
to: to,
subject: sanitizedSubject,
text: sanitizedText,
// Explicitly avoid injecting custom headers from user input
};
await transporter.sendMail(mailOptions);
return { status: 'sent' };
}
}
function isValidApiKey(key) {
// Example: compare against stored hashed keys
return key && key.length === 32;
}
module.exports = function () {
const app = this;
app.use('/email-notify', new EmailNotificationService({
name: 'email-notify',
paginate: { default: 10, max: 100 },
}));
const emailService = app.service('email-notify');
emailService.hooks({
before: {
create: [context => {
// Ensure Api Key presence and optionally scope permissions
if (!context.params.query || !context.params.query.apiKey) {
throw new Error('Api Key is required');
}
return context;
}],
},
});
};
In this example, the Api Key is validated before any email processing, and user-supplied to and subject fields are strictly validated and sanitized. Note that headers are not constructed by concatenating raw user input, preventing CRLF injection. middleBrick can verify these protections by checking that the endpoint does not reflect raw newline characters in responses and that Api Key usage is enforced through hooks.
Additionally, ensure that your OpenAPI specification defines strict schemas for email service operations. For example:
paths:
/email-notify:
post:
summary: Send notification email
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- to
- subject
- text
properties:
to:
type: string
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
subject:
type: string
maxLength: 255
text:
type: string
security:
- apiKey: []
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: Api-Key
middleBrick’s OpenAPI/Swagger analysis will flag missing patterns or insecure header usage, and its Input Validation checks will confirm that payloads are properly constrained. By combining strict input rules, header-safe construction, and Api Key gating, you reduce the risk of Email Injection while maintaining service functionality.