MEDIUM open redirectnestjsmutual tls

Open Redirect in Nestjs with Mutual Tls

Open Redirect in Nestjs with Mutual Tls — how this specific combination creates or exposes the vulnerability

An open redirect in a NestJS application using Mutual TLS (mTLS) occurs when an attacker can influence the redirect target without adequate validation. mTLS ensures the client presents a valid certificate during the TLS handshake, which the server can use for authentication or to enrich request context. However, mTLS does not automatically prevent application-level logic flaws. If endpoints in NestJS accept a URL or path parameter for redirection and reflect that value without strict allowlisting or validation, an authenticated client with a valid certificate can still be directed to arbitrary external hosts.

Consider a typical pattern where a client certificate identifies a tenant or user, and the server uses this identity to decide a redirect location. An attacker with a valid certificate could supply a crafted query or body parameter such as redirect_url or next, and if the server directly uses that value with NestJS’s Redirect or res.location(), the client may be sent to a malicious site. This becomes especially risky in workflows where mTLS is used for access control but the application assumes the redirect target is safe because the transport is authenticated. OWASP API Top 10 A05:2023 (Broken Function Level Authorization) and A01:2023 (Broken Access Control) map here, because insufficient validation enables privilege-aware clients to bypass intended post-login flows.

Real-world examples include OAuth callback endpoints or SSO flows where a client certificate is mapped to an allowed origin, but a missing allowlist permits an attacker to register a valid certificate and then provide a redirect pointing to a phishing domain. Unlike server-side request forgery, open redirect in this context does not require the server to make arbitrary network calls; it abuses trusted client-supplied URLs. The presence of mTLS may give a false sense of security, leading developers to skip strict validation of redirect targets. To detect such issues, scans should include authenticated scenarios with valid client certificates and observe whether redirect parameters are reflected without validation or constrained by a strict allowlist of domains.

Mutual Tls-Specific Remediation in Nestjs — concrete code fixes

Remediation focuses on strict validation and canonicalization of redirect targets, independent of mTLS authentication. Never trust parameters such as redirectUrl, next, or returnTo. Instead, use a strict allowlist of domains or paths and resolve relative URLs only. Below are concrete, syntactically correct examples demonstrating secure handling in NestJS with mTLS.

Example 1: Validated redirect with an allowlist

import { Controller, Get, Query, Redirect, Req } from '@nestjs/common';
import { Request } from 'express';

const ALLOWED_HOSTS = new Set(['app.example.com', 'dashboard.example.com']);

@Controller('auth')
export class AuthController {
  @Get('login/callback')
  handleLoginCallback(
    @Query('redirectUrl', { required: false }) redirectUrl: string | undefined,
    @Req() req: Request,
  ) {
    // Ensure the request includes a client certificate (mTLS enforced at the gateway)
    const clientCert = req.socket.getPeerCertificate?.();
    if (!clientCert || Object.keys(clientCert).length === 0) {
      throw new Error('mTLS client certificate required');
    }

    let target: string | undefined;
    if (redirectUrl) {
      try {
        const parsed = new URL(redirectUrl);
        if (ALLOWED_HOSTS.has(parsed.hostname)) {
          target = redirectUrl;
        }
      } catch (_) {
        // Invalid URL; ignore
      }
    }

    // Fallback to a safe default
    const safeTarget = target || '/dashboard';
    return Redirect(safeTarget);
  }
}

Example 2: Path-based redirect using route tokens

import { Controller, Get, Param, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller('tenant/:tenantId')
export class TenantController {
  @Get('welcome')
  getWelcome(@Param('tenantId') tenantId: string, @Req() req: Request) {
    const clientCert = req.socket.getPeerCertificate?.();
    if (!clientCert || Object.keys(clientCert).length === 0) {
      throw new Error('mTLS client certificate required');
    }

    // Map tenantId to a predefined route; avoid reflecting user input
    const routeMap: Record = {
      'acme': '/tenant/acme/dashboard',
      'globex': '/tenant/globex/overview',
    };

    const path = routeMap[tenantId] || '/tenant/default/dashboard';
    return Redirect(path);
  }
}

General practices

  • Require and verify the client certificate at the application layer even when enforced at the gateway, and include certificate metadata (e.g., subject or serial) in audit logs.
  • Canonicalize and validate any user-controlled input used in redirects: use the WHATWG URL API to parse and enforce same-origin or explicit allowlisted hosts.
  • Prefer server-side session tokens or opaque identifiers over raw URLs in query parameters; if URLs must be used, enforce short lifetimes and one-time use.
  • Combine mTLS with route-based authorization checks so that the identity derived from the certificate aligns with the intended redirect scope.

Frequently Asked Questions

Does mTLS alone prevent open redirect vulnerabilities in NestJS?
No. Mutual TLS authenticates the client but does not validate application-level redirect targets. You must still validate and restrict redirect URLs using allowlists and canonicalization.
How can I test my NestJS endpoints for open redirect with valid client certificates?
Use a valid client certificate to call endpoints that accept redirect parameters, and verify that the server only redirects to pre-allowed hosts. Include authenticated scan profiles in your security testing to surface logic flaws that mTLS alone does not mitigate.