siyuan-note/siyuan · error

invalid archive entry path [%s]

Error message

invalid archive entry path [%s]

What it means

validateArchiveEntryPath re-checks the fully joined destination+entry path: computing filepath.Rel(destination, entryPath) must succeed and yield a local relative path. This is a second, path-joined defense after the per-entry name check; if the joined path escapes the destination directory (or Rel fails, e.g. on mismatched volumes in Windows), extraction of that entry is refused with the offending path in the message.

Source

Thrown at kernel/api/archive.go:275

			return err
		}
	}
	for i, entry := range reader.File {
		// 解压前再次检查已有符号链接和加密身份,不复用预检阶段的路径判定结果。
		if err = validateArchiveEntryPath(destination, paths[i]); err != nil {
			return err
		}
		if err = extractWorkspaceArchiveEntry(entry, paths[i]); err != nil {
			return err
		}
	}
	return nil
}

func validateArchiveEntryPath(destination, entryPath string) error {
	rel, err := filepath.Rel(destination, entryPath)
	if err != nil || !filepath.IsLocal(rel) {
		return fmt.Errorf("invalid archive entry path [%s]", entryPath)
	}
	resolved, err := resolveArchivePath(entryPath)
	if err != nil {
		return err
	}
	resolvedDestination, err := resolveArchivePath(destination)
	if err != nil {
		return err
	}
	rel, err = filepath.Rel(resolvedDestination, resolved)
	if err != nil || !filepath.IsLocal(rel) {
		return fmt.Errorf("archive entry resolves outside destination [%s]", entryPath)
	}
	return rejectEncryptedArchivePath(entryPath)
}

func extractWorkspaceArchiveEntry(entry *archivezip.File, destination string) error {
	if entry.FileInfo().IsDir() {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Fix the archive so all entries are plain relative names without `..` segments.
  2. Ensure the unzip destination and the archive share the same drive/root on Windows.
  3. Extract with a standard tool to inspect which entry carries the bad path and remove it.

Example fix

// before
// entry name: "a/../../evil.txt"

// after
// entry name: "a/evil.txt" (relative, local under destination)
Defensive patterns

Strategy: validation

Validate before calling

clean := filepath.Clean(filepath.Join(dest, entryName))
rel, err := filepath.Rel(dest, clean)
if err != nil || !filepath.IsLocal(rel) {
    return fmt.Errorf("entry escapes destination: %s", entryName)
}

Try / catch

if err := unzipArchive(f, dest); err != nil && strings.Contains(err.Error(), "invalid archive entry path") {
    log.Warnf("entry escaped destination on same-drive check: %v", err)
}

Prevention

When it happens

Trigger: An archive entry whose cleaned/joined path (destination + name) is not inside destination — e.g. entry names containing `..` that survive name normalization, or paths that Rel cannot compute against the destination (different Windows drive roots). Called from unzipWorkspaceArchive for every entry.

Common situations: Crafted zip-slip archives using `a/../../evil` names; mixed-separator names that normalize unexpectedly; cross-drive destinations on Windows where Rel returns an error.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/f8a92fe6bd13aa93. Report an issue: GitHub.