HIGH ssrffeathersjsbasic auth

Ssrf in Feathersjs with Basic Auth

Ssrf in Feathersjs with Basic Auth — how this specific combination creates or exposes the vulnerability

Server-Side Request Forgery (SSRF) in a FeathersJS service that uses Basic Authentication can occur when user-controlled input is used to form HTTP requests to arbitrary hosts. FeathersJS applications often integrate with external services via hooks or custom services, and if those integrations accept dynamic URLs—such as a webhook URL, an API endpoint, or a proxy target—an attacker may supply a malicious hostname or IP address that the server then connects to on behalf of the authenticated client.

When Basic Auth credentials are involved, developers sometimes embed or forward them to downstream services using headers like Authorization: Basic <base64>. If the destination is attacker-controlled, the server may inadvertently relay those credentials, or the request may be redirected to an internal service that would not normally be reachable from the internet. This combination expands the attack surface: the attacker can probe internal infrastructure, access metadata services (e.g., 169.254.169.254 on cloud environments), or interact with services that only expect requests from the FeathersJS server.

In a black-box scan, middleBrick tests unauthenticated attack surfaces; if a FeathersJS endpoint accepts a URL parameter and performs outbound HTTP requests, SSRF checks include verifying whether internal or restricted endpoints can be reached. The framework itself does not introduce SSRF, but patterns such as passing user input directly to an HTTP client (e.g., axios, node-fetch) without strict validation enable the vulnerability. Common triggers include dynamic URLs in hooks, configuration fetched from user-controlled sources, or services that accept target endpoints for forwarding or transformation.

Because Basic Auth relies on base64-encoded credentials rather than opaque tokens, intercepted or proxied requests may expose credentials in logs or error responses if SSRF allows an attacker to observe outbound requests. Remediation focuses on input validation, restricting destination hosts and ports, and avoiding the propagation of authentication headers to user-defined endpoints.

Basic Auth-Specific Remediation in Feathersjs — concrete code fixes

To mitigate SSRF in FeathersJS when using Basic Authentication, ensure that any user-controlled input used to form outbound HTTP requests is strictly validated and that credentials are not forwarded to arbitrary destinations. Below are concrete code examples that demonstrate secure patterns.

Example 1: Safe service with whitelisted hosts

Define a custom service that performs an outbound request only to a pre-approved host, ignoring any user-supplied hostname for the target. This prevents an attacker from redirecting requests internally or to sensitive endpoints.

const { Service } = require('feathersjs');
const axios = require('axios');

class SafeExternalService extends Service {
  async find(params) {
    const { targetPath } = params.query;
    const allowedHost = 'api.trusted-provider.com';
    const baseUrl = `https://${allowedHost}`;

    // Ensure the requested path is safe and does not contain redirects
    if (!targetPath || !/^[a-z0-9/\-_.~]+$/i.test(targetPath)) {
      throw new Error('Invalid target path');
    }

    const url = new URL(targetPath, baseUrl);
    // Do not forward Authorization header; use an API key or app-specific token instead
    const response = await axios.get(url.toString(), {
      headers: { 'X-API-Key': process.env.TRUSTED_API_KEY },
      timeout: 5000,
    });
    return { externalData: response.data };
  }
}

module.exports = function () {
  const app = this;
  app.use('/external-safe', new SafeExternalService());
};

Example 2: Validating and sanitizing URLs in a hook

If you must accept a URL from the client, validate and sanitize it in a before hook, ensuring it points only to an allowed domain and does not redirect in a way that would expose credentials.

const axios = require('axios');

function validateOutboundUrl(url) {
  const parsed = new URL(url);
  const allowedHost = 'api.trusted-provider.com';
  if (parsed.hostname !== allowedHost) {
    throw new Error('Request target not allowed');
  }
  // Prevent schema-based SSRF bypasses
  if (!['http:', 'https:'].includes(parsed.protocol)) {
    throw new Error('Invalid protocol');
  }
  return url;
}

module.exports = {
  before: {
    all: [],
    find: [async context => {
      const { url } = context.params.query;
      context.params.url = validateOutboundUrl(url);
      // Do not include Basic Auth in the outgoing request if the target is user-defined
      const response = await axios.get(context.params.url, {
        headers: { 'X-Internal-Token': process.env.SERVICE_TOKEN },
      });
      context.result = { data: response.data };
      return context;
    }]
  }
};

Example 3: Avoid forwarding Basic Auth headers

When an outbound request is necessary, do not automatically forward the incoming Authorization header. Instead, use a scoped token or API key that is limited in scope and does not carry user credentials.

const { Service } = require('feathersjs');
const fetch = require('node-fetch');

class ProxyService extends Service {
  async create(data, params) {
    const { targetUrl } = data;
    const allowedHost = 'api.partner.com';

    if (!targetUrl.startsWith(`https://${allowedHost}`)) {
      throw new Error('Target host not permitted');
    }

    const response = await fetch(targetUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Service-Key': process.env.PARTNER_API_KEY,
      },
      body: JSON.stringify(data.payload),
    });

    if (!response.ok) {
      throw new Error('External request failed');
    }
    return response.json();
  }
}

module.exports = function () {
  const app = this;
  app.use('/proxy', new ProxyService());
};

These patterns ensure that SSRF risks are reduced by controlling destinations, avoiding credential leakage, and using purpose-specific authentication for outbound calls rather than relying on Basic Auth headers that could be exposed.

Related CWEs: ssrf

CWE IDNameSeverity
CWE-918Server-Side Request Forgery (SSRF) CRITICAL
CWE-441Unintended Proxy or Intermediary (Confused Deputy) HIGH

Frequently Asked Questions

Can SSRF in FeathersJS with Basic Auth expose internal services?
Yes. If user-controlled URLs are used without host restrictions, a FeathersJS server may make requests to internal or cloud metadata endpoints, potentially exposing services that are not publicly routable.
Does middleBrick detect SSRF in unauthenticated scans?
Yes. middleBrick tests unauthenticated attack surfaces and can identify endpoints that accept dynamic URLs for outbound requests, flagging potential SSRF and providing remediation guidance.