Skip to content

Commit 5e99618

Browse files
Potential fix for code scanning alert no. 2: Arbitrary file write extracting an archive containing symbolic links
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 90d5af4 commit 5e99618

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

internal/archive/archive.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ import (
1111
"strings"
1212
)
1313

14+
// isSafeSymlinkTarget checks if a symlink target will remain within the destPath after resolution.
15+
func isSafeSymlinkTarget(linkname, destPath string) bool {
16+
// Refuse absolute targets
17+
if filepath.IsAbs(linkname) {
18+
return false
19+
}
20+
targetPath := filepath.Join(destPath, linkname)
21+
realTarget, err := filepath.EvalSymlinks(targetPath)
22+
if err != nil {
23+
// If cannot resolve, be conservative: refuse
24+
return false
25+
}
26+
cleanDestPath := filepath.Clean(destPath)
27+
relpath, err := filepath.Rel(cleanDestPath, realTarget)
28+
return err == nil && !strings.HasPrefix(filepath.Clean(relpath), "..")
29+
}
30+
1431
// ExtractTarGz extracts a .tar.gz file to the specified destination directory
1532
func ExtractTarGz(srcPath, destPath string) error {
1633
// Open the source file
@@ -78,7 +95,10 @@ func ExtractTarGz(srcPath, destPath string) error {
7895
}
7996

8097
case tar.TypeSymlink:
81-
// Create symbolic link
98+
// Securely create symbolic link after validating target
99+
if !isSafeSymlinkTarget(header.Linkname, destPath) {
100+
return fmt.Errorf("symlink target escapes extraction directory: %s -> %s", fullPath, header.Linkname)
101+
}
82102
if err := os.Symlink(header.Linkname, fullPath); err != nil {
83103
return fmt.Errorf("failed to create symlink %s: %v", fullPath, err)
84104
}

0 commit comments

Comments
 (0)