[2.x] fix: Guard diskcache against path traversal (#9605)

**Problem**
There are several places in diskcache where resolve is called
without guards.

**Solution**
This adds guards to prevent path traversal.
This commit is contained in:
eugene yokota 2026-08-17 14:09:03 -04:00 committed by GitHub
parent e8f40d68c3
commit 0ae3c152bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 17 additions and 4 deletions

View File

@ -278,6 +278,15 @@ case class DiskActionCacheStore(base: Path, converter: FileConverter)
try Files.exists(casFile) && Digest.sameDigest(casFile, digest)
catch case _: NoSuchFileException => false
private def requireWithinBase(base: Path, target: Path, ref: HashedVirtualFileRef): Path =
val normalizedBase = base.toAbsolutePath.normalize()
val normalizedTarget = target.toAbsolutePath.normalize()
if normalizedTarget.startsWith(normalizedBase) then target
else
throw new IOException(
s"Refusing to sync ${ref.id}: resolved path $normalizedTarget is outside $normalizedBase"
)
private def getBlobs(refs: Seq[HashedVirtualFileRef]): Seq[VirtualFile] =
refs.flatMap: r =>
try
@ -343,9 +352,13 @@ case class DiskActionCacheStore(base: Path, converter: FileConverter)
val result = linkOrCopy(outPath)
afterFileWrite(ref, result, outputDirectory)
result
val resolvedPath = converter.toPath(ref) match
case p if p.isAbsolute => p
case p => outputDirectory.resolve(p)
val resolvedPath = requireWithinBase(
outputDirectory,
converter.toPath(ref) match
case p if p.isAbsolute => p
case p => outputDirectory.resolve(p),
ref
)
resolvedPath match
case p if !Files.exists(p) =>
// println(s"- syncFile: $p does not exist")
@ -407,7 +420,7 @@ case class DiskActionCacheStore(base: Path, converter: FileConverter)
// manifest contains the list of files in the dirzip, and their hashes
val m = ActionCache.manifestFromFile(mPath)
m.outputFiles.foreach: ref =>
val currentItem = converter.toPath(ref)
val currentItem = requireWithinBase(outputDirectory, converter.toPath(ref), ref)
val shortPath = outputDirectory.relativize(currentItem).toString
allPaths.remove(currentItem)
val d = Digest(ref)