Fides vulnerable to Path Traversal in Webserver API
Description
Fides is an open-source privacy engineering platform for managing the fulfillment of data privacy requests in a runtime environment, and the enforcement of privacy regulations in code. A path traversal (directory traversal) vulnerability affects fides versions lower than version 2.15.1, allowing remote attackers to access arbitrary files on the fides webserver container's filesystem. The vulnerability is patched in fides 2.15.1.
If the Fides webserver API is not directly accessible to attackers and is instead deployed behind a reverse proxy as recommended in Ethyca's security best practice documentation, and the reverse proxy is an AWS application load balancer, the vulnerability can't be exploited by these attackers. An AWS application load balancer will reject this attack with a 400 error. Additionally, any secrets supplied to the container using environment variables rather than a fides.toml configuration file are not affected by this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
ethyca-fidesPyPI | < 2.15.1 | 2.15.1 |
Affected products
1Patches
1f526d9ffb176Merge pull request from GHSA-r25m-cr6v-p9hq
3 files changed · +45 −0
src/fides/api/common_exceptions.py+4 −0 modified@@ -223,6 +223,10 @@ class SSHTunnelConfigNotFoundException(Exception): """Exception for when Fides is configured to use an SSH tunnel without config provided.""" +class MalisciousUrlException(Exception): + """Fides has detected a potentially maliscious URL.""" + + class AuthenticationError(HTTPException): """To be raised when attempting to fetch an access token using invalid credentials.
src/fides/api/main.py+20 −0 modified@@ -1,6 +1,7 @@ """ Contains the code that sets up the API. """ +import os import sys from datetime import datetime, timezone from logging import WARNING @@ -11,6 +12,7 @@ from fideslog.sdk.python.event import AnalyticsEvent from loguru import logger from starlette.background import BackgroundTask +from urllib.parse import unquote from uvicorn import Config, Server import fides @@ -20,6 +22,7 @@ log_startup, run_database_startup, ) +from fides.api.common_exceptions import MalisciousUrlException from fides.api.middleware import handle_audit_log_resource from fides.api.schemas.analytics import Event, ExtraData @@ -151,13 +154,30 @@ def read_index() -> Response: return get_admin_index_as_response() +def sanitise_url_path(path: str) -> str: + """Returns a URL path that does not contain any ../ or //""" + path = unquote(path) + path = os.path.normpath(path) + for token in path.split("/"): + if ".." in token: + logger.warning(f"Potentially dangerous use of URL hierarchy in path: {path}") + raise MalisciousUrlException() + return path + + @app.get("/{catchall:path}", response_class=Response, tags=["Default"]) def read_other_paths(request: Request) -> Response: """ Return related frontend files. Adapted from https://github.com/tiangolo/fastapi/issues/130 """ # check first if requested file exists (for frontend assets) path = request.path_params["catchall"] + logger.debug(f"Catch all path detected: {path}") + try: + path = sanitise_url_path(path) + except MalisciousUrlException: + # if a maliscious URL is detected, route the user to the index + return get_admin_index_as_response() # search for matching route in package (i.e. /dataset) ui_file = match_route(get_ui_file_map(), path)
tests/ops/util/test_api_router.py+21 −0 modified@@ -45,3 +45,24 @@ def test_non_existent_route_404( f"{V1_URL_PREFIX}/route/does/not/exist/", headers=auth_header ) assert resp_4.status_code == HTTP_404_NOT_FOUND + + def test_malicious_url( + self, + api_client: TestClient, + url, + ) -> None: + malicious_paths = [ + "../../../../../../../../../etc/passwd", + "..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd", + "%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd", + "%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd", + "..%c0%2f..%c0%2f..%c0%2f..%c0%2f..%c0%2f..%c0%2f..%c0%2f..%c0%2f..%c0%2f/etc/passwd", + ".../...//.../...//.../...//.../...//.../...//.../...//.../...//.../...//.../...//etc/passwd", + "...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2f...%2f...%2f%2fetc/passwd", + "%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//%2e%2e%2e/%2e%2e%2e//etc/passwd", + "%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2f%2e%2e%2e%2f%2e%2e%2e%2f%2fetc/passwd", + ] + for path in malicious_paths: + resp = api_client.get(f"{url}/{path}") + assert resp.status_code == 200 + assert resp.text == "<h1>Privacy is a Human Right!</h1>"
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-r25m-cr6v-p9hqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-36827ghsaADVISORY
- github.com/ethyca/fides/commit/f526d9ffb176006d701493c9d0eff6b4884e811fghsax_refsource_MISCWEB
- github.com/ethyca/fides/releases/tag/2.15.1ghsax_refsource_MISCWEB
- github.com/ethyca/fides/security/advisories/GHSA-r25m-cr6v-p9hqghsax_refsource_CONFIRMWEB
- github.com/pypa/advisory-database/tree/main/vulns/ethyca-fides/PYSEC-2023-107.yamlghsaWEB
News mentions
0No linked articles in our index yet.