{"record":{"id":"00080764a8b08246","repo":"argoproj/argo-workflows","slug":"illegal-symlink-target-s-s","errorCode":null,"errorMessage":"illegal symlink target: %s -> %s","messagePattern":"illegal symlink target: (.+?) -> (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/executor/executor.go","lineNumber":1153,"sourceCode":"\t\t\t\treturn nil\n\t\t\tcase err != nil:\n\t\t\t\treturn err\n\t\t\tcase header == nil:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttarget := filepath.Join(dest, filepath.Clean(header.Name))\n\t\t\tif !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) {\n\t\t\t\treturn fmt.Errorf(\"illegal file path: %s\", header.Name)\n\t\t\t}\n\t\t\tswitch header.Typeflag {\n\t\t\tcase tar.TypeSymlink:\n\t\t\t\t// Validate symlink target before creating it\n\t\t\t\tlinkTarget := header.Linkname\n\t\t\t\tif !filepath.IsAbs(linkTarget) {\n\t\t\t\t\tlinkTarget = filepath.Join(filepath.Dir(target), header.Linkname)\n\t\t\t\t}\n\t\t\t\tif !strings.HasPrefix(filepath.Clean(linkTarget), filepath.Clean(dest)+string(os.PathSeparator)) {\n\t\t\t\t\treturn fmt.Errorf(\"illegal symlink target: %s -> %s\", header.Name, header.Linkname)\n\t\t\t\t}\n\t\t\t\t// Create parent directory if needed\n\t\t\t\tif err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\terr := os.Symlink(header.Linkname, target)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase tar.TypeDir:\n\t\t\t\tif err := os.MkdirAll(target, 0o755); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase tar.TypeReg:\n\t\t\t\t// Before writing the file, check if the parent directory resolves outside dest\n\t\t\t\tparentDir := filepath.Dir(target)\n\n\t\t\t\t// Resolve the destination directory","sourceCodeStart":1135,"sourceCodeEnd":1171,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/executor/executor.go#L1135-L1171","documentation":"When a tar entry is a symlink, the executor resolves its target (relative to the link's directory) and verifies the cleaned target stays inside the destination directory. A symlink pointing outside dest would let extraction redirect writes, so it is rejected with 'illegal symlink target'.","triggerScenarios":"A tarball member of type TypeSymlink whose Linkname points outside the extraction root, e.g. link name 'x' with target '../../etc/passwd' or an absolute path like '/etc/passwd'.","commonSituations":"Malicious or careless artifact packaging that includes escape symlinks; archives generated on other systems containing absolute symlinks; supply-chain-poisoned third-party artifacts.","solutions":["Repackage the artifact so symlinks are relative and stay within the archive root","Inspect the tarball (tar -tvf) and remove/fix offending symlinks before uploading","Avoid loading untrusted archives as input artifacts","If the symlink legitimately points elsewhere, copy the real file into the archive instead of linking"],"exampleFix":"# before (packaging escape symlink)\nln -s /etc/passwd out.tar member\n# after (relative, in-root)\nln -s ./realfile member && tar -C root -cf out.tar .","handlingStrategy":"try-catch","validationCode":"// Check archive symlinks before uploading:\n// tar -tvf artifact.tar | grep '^l'   # list symlink members\n// tar -tvf artifact.tar | grep -E 'l.*/' # links with absolute targets","typeGuard":null,"tryCatchPattern":"if err := loadArtifacts(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"illegal symlink target\") {\n\t\t// archive contains an escaping symlink: repackage with relative links\n\t}\n}","preventionTips":["Package symlinks as relative and pointing within the archive root","Copy real files instead of symlinks when distributing artifacts","Inspect archives (tar -tvf) for symlink members from untrusted producers","Extract to a clean destination directory"],"tags":["security","artifacts","symlink","tar","path-traversal"],"backgroundTag":"zip-slip-path-traversal","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}