CVE-2024-56142
Description
pghoard is a PostgreSQL backup daemon and restore tooling that stores backup data in cloud object stores. A vulnerability has been discovered that could allow an attacker to acquire disk access with privileges equivalent to those of pghoard, allowing for unintended path traversal. Depending on the permissions/privileges assigned to pghoard, this could allow disclosure of sensitive information. This issue has been addressed in releases after 2.2.2a. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pghoardPyPI | < 2.6.1-rc | 2.6.1-rc |
Affected products
1- Range: 0.9.0, 1.0.0, 1.1.0, …
Patches
1fe9947642cc7Merge commit from fork
2 files changed · +19 −2
pghoard/webserver.py+8 −2 modified@@ -511,6 +511,12 @@ def _validate_target_path(pg_data_directory: str, target_path: str) -> None: if not xlog_file.parent.is_dir(): raise HttpResponse(f"Invalid xlog file path {target_path}, parent directory should exist", status=409) + @staticmethod + def _is_valid_xlog_path(xlog_path_str: str) -> bool: + xlog_path = Path(xlog_path_str) + return xlog_path.is_file() and not xlog_path.is_symlink() + + def get_wal_or_timeline_file(self, site: str, filename: str, filetype: str) -> None: target_path = self.headers.get("x-pghoard-target-path") if not target_path: @@ -614,8 +620,8 @@ def handle_archival_request(self, site, filename, filetype): xlog_dir = get_pg_wal_directory(site_config) xlog_path = os.path.join(xlog_dir, filename) self.server.log.debug("Got request to archive: %r %r %r, %r", site, filetype, filename, xlog_path) - if not os.path.exists(xlog_path): - self.server.log.debug("xlog_path: %r did not exist, cannot archive, returning 404", xlog_path) + if not self._is_valid_xlog_path(xlog_path): + self.server.log.debug("xlog_path: %r did not exist or contains symlinks, cannot archive, returning 404", xlog_path) raise HttpResponse("N/A", status=404) if filetype == "xlog":
test/test_webserver.py+11 −0 modified@@ -467,6 +467,17 @@ def test_get_invalid(self, pghoard, tmpdir): status = conn.getresponse().status assert status == 409 + def test_put_invalid_timeline_fails(self, pghoard, tmpdir): + wal_dir = get_pg_wal_directory(pghoard.config["backup_sites"][pghoard.test_site]) + symlink_timeline = os.path.join(str(wal_dir), "00000001.history") + secret_file = os.path.join(str(tmpdir), "config.json") + os.symlink(secret_file, symlink_timeline) + symlink_timeline_request = "/{}/timeline/00000001.history".format(pghoard.test_site) + conn = HTTPConnection(host="127.0.0.1", port=pghoard.config["http_port"]) + conn.request("PUT", symlink_timeline_request) + status = conn.getresponse().status + assert status == 404 + def test_get_invalid_retry(self, pghoard_no_mp): # inject a failure by making a static function fail failures = [0, ""]
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
4News mentions
0No linked articles in our index yet.