MEDIUM open redirectfeathersjsmongodb

Open Redirect in Feathersjs with Mongodb

Open Redirect in Feathersjs with Mongodb — how this specific combination creates or exposes the vulnerability

An Open Redirect in a Feathersjs application using Mongodb typically arises when a route accepts a user-controlled URL or hostname and uses it directly in a redirect without validation. Feathersjs, a framework built on Express, does not inherently provide redirect safeguards; if a service method returns or forwards a location derived from request data, the application can be tricked into sending the client to an arbitrary site.

Consider a profile endpoint that stores user-supplied URIs in Mongodb for redirection after login. If the stored value is not validated and the Feathersjs service performs a redirect using that value, an attacker can craft a link such as https://api.example.com/profile?returnTo=https://evil.com. The application follows the untrusted URI and issues an HTTP 302 to the malicious site. Because the data originates in Mongodb (e.g., a user document with a redirectUrl field), the persistence layer amplifies the exposure: a previously stored malicious payload can trigger redirects for subsequent logins or admin workflows.

In a typical Featherjs-Mongodb flow, the service might fetch a document by ID and use a field as the redirect target. Without validation, the redirect inherits the trust placed in the application, making the attack appear legitimate. The unauthenticated attack surface tested by middleBrick can surface such endpoints when an OpenAPI spec lacks strict format constraints on URI fields or when runtime behavior diverges from spec definitions.

Because this is a client-side redirection abuse, the impact is primarily phishing and reputation damage rather than direct data access, though it can aid in social engineering campaigns. middleBrick’s checks for Property Authorization and Input Validation can highlight missing constraints on redirect parameters, and its Output scanning can detect whether responses inadvertently expose redirect targets.

Mongodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on validating and restricting redirect destinations at the Feathersjs service layer, regardless of how the target is sourced (query, body, or Mongodb field). Do not rely on referer checks or simple hostname allowlists; use strict allowlists and canonicalization.

1. Validate against an allowlist of trusted hosts

Normalize the target URL, parse its hostname, and permit only known domains. Do not allow redirect URLs without an explicit scheme or with non-HTTP(S) schemes.

import { redirect } from 'feathers-commons'; // conceptual helper; implement validation inline if needed
import { URL } from 'url';

const allowedHosts = new Set(['app.example.com', 'www.example.com']);

function validateRedirect(url) {
  try {
    const parsed = new URL(url, 'http://localhost'); // base resolves relative URLs safely
    if (!['http:', 'https:'].includes(parsed.protocol)) {
      throw new Error('Invalid protocol');
    }
    if (!allowedHosts.has(parsed.hostname)) {
      throw new Error('Hostname not allowed');
    }
    // Optionally enforce path restrictions or remove dangerous fragments
    return parsed.toString();
  } catch (error) {
    // Reject invalid or unsafe redirects; fall back to a safe default
    return '/dashboard';
  }
}

export default {
  async create(data, params) {
    const target = validateRedirect(data.returnTo);
    // Proceed with user creation logic in Mongodb
    return {
      redirect: target
    };
  }
};

2. Use Mongodb document constraints and avoid storing raw redirect URLs

If you persist redirect URLs in Mongodb, enforce schema validation at the database/document level and avoid using raw stored values for redirects without re-validation. Prefer storing only path segments or enum-based keys that map to predefined routes.

// Mongodb document example with a restricted redirect key
const userSchema = {
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
  required: ['email'],
  properties: {
    email: { type: 'string', format: 'email' },
    // Store a safe key instead of a full URL
    redirectKey: {
      type: 'string',
      enum: ['home', 'dashboard', 'settings']
    }
  }
};

// Feathers service hook to resolve the key to a safe path
function resolveRedirectHook(context) {
  const { redirectKey } = context.result || context.data;
  const map = {
    home: '/',
    dashboard: '/dashboard',
    settings: '/settings'
  };
  const safePath = map[redirectKey] || '/';
  // Attach a verified location; do not trust stored raw URLs
  context.result.redirect = safePath;
  return context;
}

// Apply hook in your service setup
userService.hooks({
  after: {
    all: [resolveRedirectHook]
  }
});

3. Reject or sanitize Location headers in responses

If your Feathersjs app interacts with external providers that may return redirects, ensure you do not forward their Location headers blindly. Intercept and validate any Location values before passing them downstream.

// Example of sanitizing a provider redirect in a custom hook
function sanitizeLocationHook(context) {
  const location = context.result.headers && context.result.headers.location;
  if (location) {
    const safe = validateRedirect(location);
    // Replace with safe path; do not forward the original
    context.result.headers.location = safe;
  }
  return context;
}

These steps ensure that even when Mongodb stores or supplies redirect targets, the application enforces strict validation, preventing open redirect abuse while maintaining usability.

Frequently Asked Questions

Can an attacker exploit stored URLs in Mongodb even if input is validated at write time?
Yes, if validation occurs only at write time and not at redirect time, an attacker can inject a malicious URL once and it can be used later when the stored value is used for redirection. Always re-validate on each use.
Does using a relative path in Mongodb eliminate open redirect risk?
Relative paths reduce external redirection risk, but you must still validate that the path does not lead to unintended internal routes or open internal resources. Use strict path allowlists and avoid dynamic concatenation without canonicalization.