SubtitleEdit/subtitleedit · error · InvalidDataException

Archive entry is outside the extraction folder: {reader.Entr

Error message

Archive entry is outside the extraction folder: {reader.Entry.Key}

What it means

InvalidDataException from the second Zip-Slip guard: after GetFullPath, the entry resolves to a path whose relative form equals '..' or starts with '..' (+separator) or is rooted, meaning it escapes targetRoot.

Source

Thrown at src/ui/Logic/SevenZipExtractor/Unpacker.cs:431

                entryFullName = entryFullName.TrimStart(Path.DirectorySeparatorChar);
                if (string.IsNullOrEmpty(entryFullName))
                {
                    if (reader.Entry.IsDirectory)
                    {
                        Directory.CreateDirectory(dir);
                        continue;
                    }

                    throw new InvalidDataException("Archive contains an empty file entry name.");
                }

                var fullFileName = Path.GetFullPath(Path.Combine(targetRoot, entryFullName));
                var relativePath = Path.GetRelativePath(targetRoot, fullFileName);
                if (relativePath.Equals("..", StringComparison.Ordinal) ||
                    relativePath.StartsWith(".." + Path.DirectorySeparatorChar, StringComparison.Ordinal) ||
                    Path.IsPathRooted(relativePath))
                {
                    throw new InvalidDataException($"Archive entry is outside the extraction folder: {reader.Entry.Key}");
                }

                if (reader.Entry.IsDirectory)
                {
                    if (!Directory.Exists(fullFileName))
                    {
                        Directory.CreateDirectory(fullFileName);
                    }

                    continue;
                }

                var fullPath = Path.GetDirectoryName(fullFileName);
                if (fullPath == null)
                {
                    continue;
                }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Treat the archive as untrusted and reject/quarantine it; this guard is load-bearing for security.
  2. Rebuild the archive with safe, in-tree relative paths.
  3. Verify publisher and hash before extraction.

Example fix

// before
Unpacker.ExtractArchive(archivePath, dest);

// after
try { Unpacker.ExtractArchive(archivePath, dest); }
catch (InvalidDataException ex) when (ex.Message.Contains("outside the extraction folder"))
{
    Quarantine(archivePath);
    logger.LogWarning("Rejected traversal attempt in {Archive}", archivePath);
}
Defensive patterns

Strategy: validation

Validate before calling

foreach (var entry in ListEntries(archive))
{
    var full = Path.GetFullPath(Path.Combine(dest, entry.Key));
    var rel = Path.GetRelativePath(dest, full);
    if (rel.Equals("..") || rel.StartsWith(".." + Path.DirectorySeparatorChar) || Path.IsPathRooted(rel))
    {
        Quarantine(archive);
        throw new InvalidDataException($"Refusing traversal entry {entry.Key}");
    }
}

Try / catch

try { Unpacker.ExtractArchive(archive, dest); }
catch (InvalidDataException ex) when (ex.Message.Contains("outside the extraction folder"))
{
    Quarantine(archive);
    logger.LogWarning("Rejected traversal archive {Archive}", archive);
}

Prevention

When it happens

Trigger: Archive entries like '../evil.dll', '..\\..\\system32\\x', or nested traversal sequences that resolve above targetRoot despite not being absolute.

Common situations: Malicious archives designed to escape the extraction folder, or archives built from a parent directory.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/939ae5fcd2be216f. Report an issue: GitHub.