Fix SSRF (Server Side Request Forgery) in Feathers
SSRF in FeathersJS commonly manifests when custom hooks or services process user-supplied URLs to fetch external resources, such as webhooks or metadata. If input isn't sanitized, an attacker can force the server to scan internal ports, access cloud metadata services (IMDS), or hit internal APIs that aren't exposed to the internet. As a Senior Researcher, my rule is simple: never trust a URL provided by the client without strict allowlisting and DNS resolution checks.
The Vulnerable Pattern
const axios = require('axios');
// A Feathers hook that fetches a user-provided image URL module.exports = function (options = {}) { return async context => { const { imageUrl } = context.data; // VULNERABILITY: Blindly fetching a user-controlled URL const response = await axios.get(imageUrl); context.data.metadata = response.data; return context; }; };
The Secure Implementation
The fix implements a defense-in-depth strategy. First, we use the native 'URL' constructor to parse the input, preventing basic obfuscation bypasses. Second, we enforce 'https:' to prevent protocol smuggling (like file:// or gopher://). Third, we implement a strict 'ALLOWED_HOSTS' allowlist. For production environments where dynamic URLs are required, you must resolve the hostname to an IP and verify it is not in a private/reserved CIDR block (e.g., 10.0.0.0/8, 127.0.0.1) before the request is made to prevent DNS Rebinding and internal network probing.
const axios = require('axios'); const { URL } = require('url'); const { Forbidden } = require('@feathersjs/errors');const ALLOWED_HOSTS = [‘trusted-cdn.com’, ‘api.partner.io’];
module.exports = function (options = {}) { return async context => { const { imageUrl } = context.data; if (!imageUrl) return context;
try { const parsed = new URL(imageUrl); // 1. Protocol Enforcement if (parsed.protocol !== 'https:') { throw new Forbidden('Only HTTPS is allowed'); } // 2. Strict Host Allowlisting if (!ALLOWED_HOSTS.includes(parsed.hostname)) { throw new Forbidden('Unauthorized host'); } const response = await axios.get(imageUrl, { timeout: 2000, maxContentLength: 1024 * 1024, // 1MB limit validateStatus: (status) => status === 200 }); context.data.metadata = response.data; } catch (err) { throw new Forbidden('Invalid or malicious URL'); } return context;
}; };
Your Feathers API
might be exposed to SSRF (Server Side Request Forgery)
74% of Feathers apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.