Aug 27, 2026·7 min read·2 visits
A parser differential between WebOb and Python's urljoin on modern runtimes allows unauthenticated attackers to bypass open redirect protections using leading spaces or control characters.
An open redirect vulnerability exists in WebOb before version 1.8.11 due to a parser differential between WebOb's validation logic and Python's standard urllib.parse.urljoin() function. Under Python 3.10+, the urljoin function strips leading and trailing space characters and C0 control characters, which allowed specially crafted inputs to bypass WebOb's prefix checks while still resolving as off-host redirects.
WebOb is an essential Python library providing wrappers for WSGI request and response objects, serving as a foundational dependency for web frameworks like Pyramid and various Pylons-based applications. Due to its role in parsing HTTP parameters and constructing HTTP response headers, WebOb is positioned at a critical junction of the application's attack surface. Specifically, components responsible for generating redirections, such as the Location header handler and redirection exception classes, rely on parsing and resolving URLs safely.
CVE-2026-54770 represents a recurring design vulnerability in WebOb's validation logic, categorized under CWE-601 (URL Redirection to Untrusted Site). When applications accept user-supplied URLs to redirect users after specific actions, they must ensure that the destination remains within the boundaries of the trusted host. If an attacker can manipulate the destination to point to an arbitrary external domain, the application becomes an open redirector.
This flaw arises from a parser differential between WebOb's validation routines and the underlying URL parsing library in Python 3.10+. Because these two systems interpret special characters differently, validation checks can be bypassed, resulting in unauthenticated remote users redirecting victims to arbitrary external domains. The scope of this vulnerability extends beyond simple phishing, potentially facilitating OAuth flow exploits and token theft in single-sign-on (SSO) environments.
The root cause of CVE-2026-54770 lies in a parser differential between WebOb's preliminary sanitization checks and the standard behavior of urllib.parse.urljoin() in Python 3.10 and above. To prevent protocol-relative redirects (e.g., //evil.com), WebOb attempts to detect if a redirection path begins with double slashes. If detected, the prefix is neutralized to prevent user agents from interpreting the target as an off-host authority.
However, in modern Python runtimes (3.10+), the standard library's urllib.parse.urljoin() has been updated to align with the WHATWG URL specification. This specification dictates that a parser must strip leading and trailing C0 control characters (ASCII 0x00 through 0x1F) as well as the standard space character (ASCII 0x20) before performing reference resolution. Additionally, tabs and newline characters are removed from anywhere within the URL string.
This creates a classic validation-execution gap. When an attacker prefixes a protocol-relative URL with a space or a control character, such as " //evil.com", WebOb's validation logic executes first on the raw string. Since the string starts with a space rather than "//", the neutralization routine is bypassed. Subsequently, the string is passed to urllib.parse.urljoin(), which strips the leading space, leaving a valid protocol-relative URL. The library then resolves this relative URL against the local origin, producing an absolute redirect to http://evil.com.
To address this persistent validation gap, WebOb completely refactored its URL resolution mechanism in version 1.8.11. The maintainers determined that standardizing on Python's urllib.parse.urljoin() was fundamentally unsafe because the standard library's parsing rules are coupled with runtime-dependent behaviors and browser-emulation stripping routines.
Instead of patching around individual characters, WebOb implemented a custom, strict RFC 3986-compliant reference resolution parser in src/webob/util.py. The new function, _split_uri_reference, parses URLs without stripping leading or trailing spaces or C0 control characters, ensuring that validation and execution parse the exact same string:
def _split_uri_reference(uri):
# Split a URI reference into its five components.
# Unlike urllib.parse.urlsplit(), no characters are ever removed
# from the reference: ASCII tab/CR/LF and leading or trailing C0
# control and space characters are treated like any other character.
scheme = authority = query = fragment = None
rest, sep, token = uri.partition("#")
if sep:
fragment = token
rest, sep, token = rest.partition("?")
if sep:
query = token
token, sep, candidate = rest.partition(":")
if sep and _URI_SCHEME_RE.match(token):
scheme = token
rest = candidate
if rest.startswith("//"):
end = rest.find("/", 2)
if end == -1:
authority, rest = rest[2:], ""
else:
authority, rest = rest[2:end], rest[end:]
return scheme, authority, rest, query, fragmentAdditionally, the patch consolidated the redirection paths within webob.exc._HTTPMove (which covers classes like HTTPFound). Historically, these exceptions directly invoked urljoin() without routing through the safe _make_location_absolute() path. The updated logic forces all redirections to use the strict validation routine, blocking variants of the bypass.
Exploitation of CVE-2026-54770 requires no authentication and can be performed remotely via standard HTTP requests. The primary prerequisite is that the target application must expose an endpoint that dynamically redirects users based on input parameter values, such as a "next" or "return_to" parameter.
An attacker crafts a URL targeting this endpoint, injecting a payload that includes a leading space or control character. For instance, using the URL-encoded representation of a space (%20), the parameter is defined as "%20//attacker-controlled.com". When the backend application initiates the redirection exception, WebOb handles the path resolution.
When the victim accesses the crafted link and performs the expected action, their browser receives a 302 Found response containing a Location header pointing directly to the malicious domain. Because the initial domain in the link was trusted, the victim has no indication of the impending redirection, making this an extremely effective vector for credential harvesting.
The security impact of CVE-2026-54770 is primarily rated as medium, with a CVSS v3.1 score of 6.1. Although the vulnerability does not allow remote code execution or direct data compromise on the server, its role as an initial access vector is significant.
Open redirects are frequently chained with other vulnerabilities to bypass security controls. In OAuth 2.0 and OpenID Connect (OIDC) implementations, client applications register trusted redirect URIs. If a registered URI is vulnerable to an open redirect, an attacker can construct a flow that diverts the authorization code or implicit token to an external server. This results in complete account takeovers on the target application.
Furthermore, because the redirect originates from a trusted host, security filters, email scanners, and users are highly likely to trust the initial link. This trust is exploited during spearphishing campaigns to deliver malware or present highly convincing spoofed login interfaces to targets, directly impacting the integrity of user credentials.
The definitive remediation for CVE-2026-54770 is to upgrade the WebOb library to version 1.8.11 or later. This version completely replaces the vulnerable parsing dependencies with a strict, consistent internal parser that removes the parser differential.
If patching is not immediately feasible due to legacy system constraints, organizations can implement defense-in-depth measures at the application layer or via Web Application Firewalls (WAFs). A custom middleware or WAF rule can be applied to inspect all redirect targets and block strings containing leading spaces or C0 control characters. For example, the following regular expression can be used to identify anomalous redirection patterns:
^\s+[\/\\]{2,}
Additionally, developers should avoid blindly passing user input to redirection mechanisms. Implementing an allowlist of permitted destination domains or path prefixes is the most robust application-layer defense. If only local redirects are allowed, the application should strictly enforce that the path begins with a single slash "/" and is not followed by a second slash, space, or control character.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
WebOb Pylons Project | < 1.8.11 | 1.8.11 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-601 |
| Attack Vector | Network |
| CVSS v3.1 | 6.1 (Medium) |
| EPSS Score | 0.00339 (0.34%) |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
| Impact | Open Redirect / Phishing |
A web application accepts a user-controlled input that specifies a link to an external site, and uses that input in a redirect. This simplifies phishing attacks or facilitates credential theft.
An input buffering vulnerability exists in the aiosmtplib asynchronous SMTP client library before version 5.1.2. When upgrading a plaintext connection to TLS via STARTTLS, the library processes buffered plaintext responses after transport negotiation has completed. This behavior allows a network-positioned attacker to inject spoofed server responses prior to negotiation, leading to command/response desynchronization, arbitrary capability injection, and potential credential theft.
Prior to version 1.0.0, the n8n-nodes-sqlite3 integration exposed the db_path parameter as an unrestricted node parameter. By default, n8n node parameters allow the evaluation of dynamic data expressions, meaning untrusted external input could be mapped to the database path. This vulnerability allows an external attacker to control which SQLite database file the n8n backend process attempts to open, leading to directory traversal outside of the intended directory context.
A client-side open redirect vulnerability has been identified in the Kargo user interface. The flaw resides in the handling of OpenID Connect (OIDC) login and token renewal flows, where the application extracts an unvalidated destination path from the redirectTo query parameter. Attackers can exploit this to redirect authenticated users to arbitrary external domains.
A Server-Side Template Injection (SSTI) vulnerability in the Silverstripe Advanced Workflow module allows authenticated attackers with workflow authoring permissions to achieve arbitrary code execution. By manipulating the NotifyUsersWorkflowAction.EmailTemplate field, attackers can inject template code that dynamically executes arbitrary PHP commands via the core translation helper interpolation path.
A path traversal and arbitrary file write vulnerability exists in the libreoffice-convert Node.js package in all versions prior to 1.8.2. The convertWithOptions function fails to validate or sanitize the caller-controlled options.fileName parameter, allowing directory traversal sequences to write files outside the temporary directory.
Crossplane's runtime package manager engine contains a Time-of-Check to Time-of-Use (TOCTOU) race condition in its container signature verification pipeline. When Crossplane parses package definitions using dynamic tag-based references, it resolves the tag on the remote OCI registry twice: once during the signature verification step (the 'Check' phase) and once during the fetch and install step (the 'Use' phase). An attacker controlling the destination OCI registry can exploit this vulnerability by serving a validly signed benign image for the verification phase, and then dynamically swapping the tag to point to an unsigned, malicious package during the fetch phase.