Prevent path traversal in DescriptorIndexCollector#478
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request hardens DescriptorIndexCollector.fetchRemoteFiles against path traversal by validating remote file names and ensuring computed destination paths remain under the configured local descriptor directory before writing.
Changes:
- Normalizes the configured local descriptor directory into a canonical containment root (
localDirPath). - Rejects remote entries with invalid file names (empty,
./.., or containing path separators) and skips them with warnings. - Normalizes destination and temp file paths and skips any entries that resolve outside the local directory.
Comments suppressed due to low confidence (1)
backend/src/main/java/org/torproject/descriptor/index/DescriptorIndexCollector.java:117
filepathname.replace(filename, "")is unsafe for deriving the parent directory: it replaces all occurrences offilename, which can yield an unintended (or even absolute) path. Becausemkdirs()is executed before thestartsWith(localDirPath)containment check, a maliciousfilenamethat matches a segment in the configured remote path (e.g.,recent) could cause directory creation attempts outsidelocalDiror abort collection unexpectedly. Prefer deriving the parent path using path operations (e.g., takePaths.get(filepathname).getParent()), then resolve againstlocalDirPathand perform containment validation before creating directories.
File filepath = new File(localDir,
filepathname.replace(filename, ""));
long lastModifiedMillis = entry.getValue().lastModifiedMillis();
if (lastModifiedMillis < minLastModified
|| (locals.containsKey(filepathname)
&& locals.get(filepathname) >= lastModifiedMillis)) {
continue;
}
if (!filepath.exists() && !filepath.mkdirs()) {
logger.warn("Cannot create local directory {} to store remote file {}. "
+ "Aborting descriptor collection.", filepath, filename);
return false;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
|
@copilot Add test cases for the changed functionality ensuring that genuine activity still works as intended while path traversal is prevented. |
Agent-Logs-Url: https://github.com/TorMap/tormap/sessions/41468e89-b648-4fd8-8a8c-c6c4c0211859 Co-authored-by: JuliusHenke <23460202+JuliusHenke@users.noreply.github.com>
Added targeted regression coverage in |
Motivation
.., absolute paths, or separators and be used to write files outside the configured descriptor download directory, enabling a path traversal overwrite attack.Description
localDirtoPath localDirPath = localDir.toPath().toAbsolutePath().normalize()and used it as the canonical containment root.null, empty,.or.., or contain path separators (/or\) and skip those entries with a warning.startsWith(localDirPath)before performing the download and rename, skipping and logging any entries that resolve outside the local directory.Testing
./gradlew compileJavafrom thebackend/directory, which failed in this environment with Gradle reportingWhat went wrong: 25.0.1../gradlew :backend:compileJavafrom the repo root failed because a wrapper was not present at the project root in this environment.DescriptorIndexCollector.fetchRemoteFiles.Codex Task