Ssrf Server Side in Feathersjs
How SSRF Manifests in FeathersJS
Server-Side Request Forgery (SSRF) in FeathersJS occurs when an application accepts user-controlled URLs and makes internal requests without proper validation. In FeathersJS, this vulnerability often emerges through service hooks, external API integrations, or custom endpoints that process user input for HTTP requests.
A common pattern in FeathersJS applications involves using hooks to enrich data by fetching external resources. Consider this vulnerable pattern:
app.service('users').hooks({
before: {
get: [
async context => {
const profileUrl = context.params.query.profileUrl;
const response = await fetch(profileUrl);
const profileData = await response.json();
context.result.profile = profileData;
}
]
}
});This hook fetches a user profile from a URL provided in the query parameters. An attacker could supply http://localhost:3306 to access the database, http://169.254.169.254 to access AWS metadata, or file:///etc/passwd to read local files.
FeathersJS's flexible service architecture makes SSRF particularly dangerous. Services can be configured to proxy requests, and hooks can execute arbitrary code before service methods. The app.configure() method allows loading plugins that might introduce SSRF vulnerabilities if they accept user input for URLs.
Cloud metadata services are a prime SSRF target. AWS, GCP, and Azure expose sensitive instance metadata at predictable internal URLs. A FeathersJS application running on AWS might inadvertently expose:
app.service('metadata').hooks({
before: {
find: [
async context => {
const metadataUrl = 'http://169.254.169.254/latest/metaadata/';
const response = await fetch(metadataUrl + context.params.query.path);
context.result = await response.json();
}
]
}
});An attacker could traverse the metadata service to extract IAM credentials, SSH keys, or instance configuration.
FeathersJS-Specific Detection
Detecting SSRF in FeathersJS requires examining both the application code and runtime behavior. middleBrick's black-box scanning approach is particularly effective for FeathersJS applications because it tests the actual running API without requiring source code access.
middleBrick scans for SSRF by sending crafted payloads to endpoints that might accept URLs. For FeathersJS applications, it tests common patterns including:
- Query parameters named
url,callback,proxy, or similar - Request bodies containing URL fields
- Headers that might control request destinations
- Configuration endpoints that might accept service URLs
The scanner attempts connections to internal network ranges, cloud metadata services, and common internal ports. For FeathersJS specifically, middleBrick recognizes the framework's service hook patterns and tests endpoints that follow typical Feathers naming conventions.
Beyond automated scanning, manual detection in FeathersJS involves:
const vulnerableHooks = [
// Hooks that fetch from user-controlled URLs
'before:get:fetchProfile',
'before:create:validateExternalData',
'after:find:enrichWithExternalResources'
];Code review should flag any use of fetch(), axios, or HTTP clients where the URL comes from user input. The context.params object in FeathersJS hooks is particularly dangerous as it can contain arbitrary query parameters.
middleBrick's SSRF detection includes testing for blind SSRF vulnerabilities where the application might make requests without returning the content. It uses out-of-band techniques to detect when internal requests are made, even when responses aren't directly returned to the user.
FeathersJS-Specific Remediation
Remediating SSRF in FeathersJS requires a defense-in-depth approach. The most effective strategy combines input validation, allowlisting, and architectural controls.
Input validation should be the first line of defense. For URL inputs in FeathersJS hooks:
const validateUrl = (url) => {
try {
const parsed = new URL(url);
// Block private IP ranges
const privateRanges = [
/^10\./,
/^172\.(1[6-9]|2[0-9]|3[0-1])\./,
/^192\.168\./,
/^127\./,
/^169\.254\./,
/^0\.0\.0\.0/,
/^255\.255\.255\.255/
];
if (privateRanges.some(regex => regex.test(parsed.host))) {
throw new Error('Private IP address not allowed');
}
// Allow only specific protocols
if (!['http:', 'https:'].includes(parsed.protocol)) {
throw new Error('Only HTTP/HTTPS allowed');
}
return true;
} catch (error) {
return false;
}
};Implement this validation in a reusable hook:
const validateExternalUrl = async context => {
const urlParam = context.params.query.url ||
context.data?.url ||
context.params.url;
if (urlParam && !validateUrl(urlParam)) {
throw new errors.BadRequest('Invalid or blocked URL');
}
};
// Apply to all services that might process URLs
app.service('users').hooks({
before: {
all: [validateExternalUrl]
}
});For FeathersJS applications that must access external resources, use a proxy service with strict controls:
const proxyService = {
async get(url) {
// Validate URL
if (!validateUrl(url)) {
throw new Error('Invalid URL');
}
// Set timeout to prevent slowloris attacks
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(url, {
signal: controller.signal,
headers: {
'User-Agent': 'middleBrick-Proxy/1.0'
}
});
return await response.text();
} finally {
clearTimeout(timeout);
}
}
};Architectural remediation involves redesigning the application to eliminate URL parameters entirely. Instead of accepting URLs from users, maintain an allowlist of approved external services:
const APPROVED_SERVICES = {
'github-profile': 'https://api.github.com/users/',
'twitter-profile': 'https://api.twitter.com/2/users/',
'openai-api': 'https://api.openai.com/v1/'
};middleBrick's continuous monitoring in the Pro tier can verify that SSRF mitigations remain effective as the codebase evolves. The scanner runs on a schedule you configure, alerting you if new SSRF vulnerabilities are introduced.