Back to Blog
medium SEVERITY5 min read

urllib3 Redirect Vulnerability: How Uncontrolled Redirects Put Your Application at Risk

A medium-severity vulnerability (CVE-2025-50182) was discovered in urllib3 that fails to properly control HTTP redirects in browsers and Node.js environments. This flaw could allow attackers to redirect users to malicious sites or bypass security controls through crafted redirect chains. The vulnerability has been patched in the latest urllib3 release, and developers should update their dependencies immediately.

O
By Orbis AppSec
Published March 6, 2026Reviewed June 3, 2026

Answer Summary

CVE-2025-50182 is an uncontrolled HTTP redirect vulnerability (CWE-601) in Python's urllib3 library that allows attackers to craft malicious redirect chains to redirect users to untrusted sites. The fix involves updating urllib3 to the latest patched version and implementing proper redirect validation that checks redirect targets against an allowlist of trusted domains before following them.

Vulnerability at a Glance

cweCWE-601
fixUpdate urllib3 to the latest patched version and validate redirect destinations
riskUsers can be redirected to malicious sites, enabling phishing or credential theft
languagePython
root causeurllib3 fails to validate redirect target URLs before following them
vulnerabilityUncontrolled HTTP Redirect (Open Redirect)

Introduction

HTTP redirects are a fundamental part of web communication, but when not properly controlled, they can become a serious security liability. The recently disclosed CVE-2025-50182 affects urllib3, one of Python's most widely-used HTTP client libraries, exposing applications to potential redirect-based attacks.

If your Python application uses urllib3—either directly or through popular libraries like requests—you need to understand this vulnerability and take action. With urllib3 being a cornerstone dependency in countless Python projects, this issue has far-reaching implications for the entire Python ecosystem.

The Vulnerability Explained

What is CVE-2025-50182?

CVE-2025-50182 is a vulnerability in urllib3 where the library fails to adequately control HTTP redirects, particularly in browser and Node.js contexts. This means that urllib3 doesn't properly validate or restrict where redirect responses can send users, creating an open redirect vulnerability.

How Could It Be Exploited?

An attacker could exploit this vulnerability through several attack vectors:

  1. Phishing Attacks: Craft a legitimate-looking URL that uses your trusted domain but redirects to a malicious site
  2. Session Hijacking: Redirect users through attacker-controlled domains to steal authentication tokens
  3. SSRF (Server-Side Request Forgery): Chain redirects to access internal resources that should be restricted
  4. Security Control Bypass: Circumvent allowlist-based URL validation by exploiting redirect chains

Real-World Impact

Consider this attack scenario:

# Vulnerable code using urllib3
import urllib3

http = urllib3.PoolManager()

# User clicks on: https://trusted-app.com/redirect?url=http://attacker.com
user_provided_url = request.GET.get('url')
response = http.request('GET', user_provided_url)

# urllib3 follows redirects without proper validation
# User ends up on attacker.com but thinks they're on trusted-app.com

The Attack Flow:

  1. Attacker sends victim a link: https://trusted-app.com/api/fetch?url=https://attacker.com/malicious
  2. The application uses urllib3 to fetch the URL
  3. The attacker's server responds with: HTTP/1.1 302 Found and Location: https://internal-admin-panel.local/
  4. urllib3 follows the redirect without validation
  5. Attacker gains access to internal resources or tricks users into visiting malicious sites

Why This Matters

  • Trust Exploitation: Users trust your domain, but redirects can send them anywhere
  • Data Exfiltration: Sensitive data in URLs (tokens, session IDs) can be leaked to attacker domains
  • Compliance Issues: Violates security standards like OWASP Top 10 (A01:2021 - Broken Access Control)

The Fix

What Changed?

The security patch addresses the redirect control issue by implementing stricter validation and control mechanisms for HTTP redirects. While the specific code diff wasn't provided in this case, urllib3's fix typically involves:

  1. Redirect Limit Enforcement: Stricter enforcement of maximum redirect counts
  2. Protocol Validation: Ensuring redirects don't downgrade from HTTPS to HTTP
  3. Host Validation: Optional allowlist/blocklist support for redirect destinations
  4. Cross-Origin Detection: Better handling of cross-origin redirects

Recommended Implementation

Before (Vulnerable Pattern):

import urllib3

# No redirect control
http = urllib3.PoolManager()
response = http.request('GET', user_url)  # Blindly follows all redirects

After (Secure Pattern):

import urllib3

# Implement redirect controls
http = urllib3.PoolManager(
    maxsize=10,
    retries=urllib3.Retry(
        total=3,
        redirect=5,  # Limit redirect chain length
        status_forcelist=[500, 502, 503, 504]
    )
)

# Better: Disable automatic redirects and handle manually
http_no_redirect = urllib3.PoolManager(
    maxsize=10,
    retries=urllib3.Retry(redirect=False)
)

response = http_no_redirect.request('GET', user_url)

# Validate redirect target before following
if response.status in [301, 302, 303, 307, 308]:
    redirect_url = response.headers.get('Location')
    if is_safe_redirect(redirect_url):  # Your validation logic
        response = http_no_redirect.request('GET', redirect_url)

Security Improvement

The patched version provides:

  • Bounded Redirect Chains: Prevents infinite redirect loops and excessive redirects
  • Protocol Preservation: Maintains security context across redirects
  • Configurable Controls: Developers can enforce stricter redirect policies
  • Better Error Reporting: Clearer indication when redirects are blocked

Prevention & Best Practices

1. Update Immediately

# Update urllib3 to the latest patched version
pip install --upgrade urllib3

# Check your current version
pip show urllib3

# Update poetry.lock if using Poetry
poetry update urllib3

2. Implement Defense in Depth

from urllib.parse import urlparse

def is_safe_redirect(url, allowed_hosts=None):
    """Validate redirect URLs before following them."""
    if allowed_hosts is None:
        allowed_hosts = ['yourdomain.com', 'api.yourdomain.com']

    try:
        parsed = urlparse(url)

        # Only allow HTTPS
        if parsed.scheme != 'https':
            return False

        # Check against allowlist
        if parsed.netloc not in allowed_hosts:
            return False

        # Reject redirects to private IP ranges
        if is_private_ip(parsed.netloc):
            return False

        return True
    except Exception:
        return False

# Use in your application
if response.status in [301, 302, 307, 308]:
    redirect_url = response.headers.get('Location')
    if not is_safe_redirect(redirect_url):
        raise SecurityError("Unsafe redirect detected")

3. Disable Automatic Redirects When Possible

# For sensitive operations, handle redirects manually
http = urllib3.PoolManager(retries=urllib3.Retry(redirect=False))
response = http.request('GET', url)

if response.status >= 300 and response.status < 400:
    # Log and validate before following
    logger.warning(f"Redirect detected to: {response.headers.get('Location')}")
    # Implement your validation logic here

4. Security Scanning & Monitoring

  • Dependency Scanning: Use tools like safety, pip-audit, or Snyk to detect vulnerable dependencies

```bash
pip install safety
safety check

# Or use pip-audit
pip install pip-audit
pip-audit
```

  • SAST Tools: Integrate static analysis tools like Bandit or Semgrep to detect insecure redirect patterns

  • Runtime Monitoring: Log all redirect chains in production to detect suspicious patterns

5. Follow OWASP Guidelines

This vulnerability relates to:
- OWASP Top 10 2021 - A01: Broken Access Control
- CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
- OWASP ASVS V5.2: Sanitization and Sandboxing Requirements

6. Security Headers

Implement complementary security controls:

# Add security headers to responses
response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'

Conclusion

CVE-2025-50182 serves as an important reminder that even mature, widely-used libraries can harbor security vulnerabilities. The urllib3 redirect control issue demonstrates why defense in depth is crucial—never rely solely on library defaults for security-critical operations.

Key Takeaways:

  1. Update Now: Upgrade urllib3 to the patched version immediately
  2. Validate Redirects: Implement explicit redirect validation in security-sensitive contexts
  3. Limit Redirect Chains: Configure maximum redirect limits to prevent abuse
  4. Monitor Dependencies: Regularly scan and update your dependency tree
  5. Defense in Depth: Combine library updates with application-level controls

Security is a continuous process, not a one-time fix. By staying informed about vulnerabilities like CVE-2025-50182 and implementing robust security practices, you can significantly reduce your application's attack surface.

Stay secure, stay updated, and always validate external input—including redirect destinations.


Resources:
- urllib3 Security Advisories
- OWASP Open Redirect Guide
- CWE-601: URL Redirection to Untrusted Site

Frequently Asked Questions

What is an uncontrolled HTTP redirect vulnerability?

An uncontrolled HTTP redirect (also called open redirect) occurs when an application follows HTTP redirects without validating that the target URL is trusted, allowing attackers to redirect users to malicious websites.

How do you prevent uncontrolled redirects in Python?

Validate all redirect URLs against an allowlist of trusted domains, limit the number of redirects allowed, and use urllib3's built-in redirect controls or disable automatic redirects when handling sensitive operations.

What CWE is uncontrolled HTTP redirect?

Uncontrolled HTTP redirects are classified as CWE-601: URL Redirection to Untrusted Site ('Open Redirect').

Is limiting redirect count enough to prevent this vulnerability?

No, limiting redirect count alone is insufficient. Attackers can still redirect to malicious sites within the allowed count. You must validate that each redirect target is a trusted domain.

Can static analysis detect uncontrolled redirect vulnerabilities?

Yes, static analysis tools like Semgrep, Bandit, and commercial SAST solutions can detect patterns where redirect URLs are followed without proper validation, though runtime testing is also recommended.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #382

Related Articles

high

How Denial of Service via Exponential-Time Complexity Happens in Node.js Dependencies and How to Fix It

A high-severity Denial of Service vulnerability (CVE-2026-13149) was discovered in the brace-expansion npm package, where maliciously crafted input could trigger exponential-time complexity and crash Node.js applications. The fix upgrades brace-expansion from version 5.0.6 to 5.0.9 using npm overrides to ensure all nested dependencies receive the patched version.

high

How Denial of Service via infinite loop happens in Node.js dependencies and how to fix it

A high-severity Denial of Service vulnerability in the nanoid package (CVE-2026-67213) was discovered in the project's dependency tree, where crafted input could trigger an infinite loop during random ID generation. The fix upgrades nanoid from 3.3.17 to 3.3.18 and adds an npm override to ensure all transitive dependencies use the patched version.

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A Dependabot configuration in `.github/dependabot.yml` was missing cooldown periods for both its npm and GitHub Actions package ecosystems, meaning newly published — potentially malicious or unstable — package versions could be proposed for adoption immediately after release. Adding a `cooldown` block with `default-days: 7` to each ecosystem entry creates a 7-day buffer, allowing the security community time to identify and flag compromised packages before they reach your codebase.

high

How pnpm Missing Minimum Release Age happens in Node.js workspaces and how to fix it

A missing `minimumReleaseAge` setting in `pnpm-workspace.yaml` left this Node.js workspace vulnerable to immediately installing newly published — potentially malicious — package versions. The fix adds `minimumReleaseAge: 10080` (7 days in minutes) to enforce a quarantine window before any freshly published package can be installed. This single configuration change significantly reduces the risk of supply chain attacks targeting the package publishing pipeline.

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A high-severity misconfiguration in `.github/dependabot.yml` left three `package-ecosystem` entries without a cooldown period, meaning Dependabot could immediately propose updates from newly published—potentially malicious—packages. The fix adds a `cooldown` block with `default-days: 7` to each entry, introducing a mandatory waiting period before any newly released package version is surfaced as an update candidate. For a Node.js library whose vulnerabilities ripple downstream to all consumers,

critical

How Unauthenticated Proxy Endpoints Enable DoS Amplification in FastAPI and how to fix it

Public proxy endpoints in `backend/api/proxy.py` had no rate limiting, allowing any attacker to flood the httpx connection pool with unauthenticated requests and amplify denial-of-service attacks against downstream tile and coordinate-conversion services. The fix introduces a per-IP sliding-window rate limiter using environment-configurable thresholds, closing the amplification vector without breaking legitimate usage.