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
- Fix the archive so all entries are plain relative names without `..` segments.
- Ensure the unzip destination and the archive share the same drive/root on Windows.
- 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
- Ensure archive entry names contain no `..` segments after cleaning
- Extract on the same drive/root as the archive paths on Windows
- Run the same Rel/IsLocal check in client-side pre-validation
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
- archive entry resolves outside destination [%s]
- symlink resolves into encrypted notebook [%s]
- path belongs to encrypted notebook [%s]
- invalid archive entry [%s]
- marketplace package contains too many files
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/f8a92fe6bd13aa93.
Report an issue: GitHub.