{"record":{"id":"a5658be2a2e33888","repo":"slimtoolkit/slim","slug":"source-is-symlink","errorCode":null,"errorMessage":"source is symlink","messagePattern":"source is symlink","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/docker/dockerutil/dockerutil.go","lineNumber":574,"sourceCode":"\t\t}\n\n\t\terr = dclient.RemoveContainer(removeOptions)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"dockerutil.CopyToVolume: dclient.RemoveContainer() error = %v\\n\", err)\n\t\t}\n\t}\n\n\tcleanSource, err := filepath.EvalSymlinks(source)\n\tif err != nil {\n\t\tlog.Errorf(\"dockerutil.CopyToVolume: filepath.EvalSymlinks(%s) error = %v\", source, err)\n\t\trmContainer()\n\t\treturn err\n\t}\n\n\tif fsutil.IsSymlink(cleanSource) {\n\t\tlog.Errorf(\"dockerutil.CopyToVolume: source is a symlink = %s\", cleanSource)\n\t\trmContainer()\n\t\treturn fmt.Errorf(\"source is symlink\")\n\t}\n\n\ttarData, err := archive.Tar(cleanSource, archive.Uncompressed)\n\tif err != nil {\n\t\tlog.Errorf(\"dockerutil.CopyToVolume: archive.Tar() error = %v\", err)\n\t\trmContainer()\n\t\treturn err\n\t}\n\n\ttargetPath := volumeBasePath\n\tif dstRootDir != \"\" {\n\t\tdirData, err := GenStateDirsTar(dstRootDir, dstTargetDir)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"dockerutil.CopyToVolume: GenStateDirsTar() error = %v\", err)\n\t\t\trmContainer()\n\t\t\treturn err\n\t\t}\n","sourceCodeStart":556,"sourceCodeEnd":592,"githubUrl":"https://github.com/slimtoolkit/slim/blob/81940d17fa112cc678e32209214bcb2355cb3004/pkg/docker/dockerutil/dockerutil.go#L556-L592","documentation":"CopyToVolume copies a host directory/file into a Docker volume via a helper container. Before archiving, it checks whether the resolved source path is a symlink with fsutil.IsSymlink and refuses to proceed. This guard exists because copying a symlinked source could pull in unintended target content or escape the expected copy root, so the library treats symlinks as unsafe inputs.","triggerScenarios":"Calling dockerutil.CopyToVolume (directly or via DoArchiveState / CreateVolumeWithData) with a source path that resolves to a symlink, e.g. passing /var/run/docker.sock, a /tmp symlinked directory, or a user-supplied path that is a soft link.","commonSituations":"macOS/OSX temp dirs (/tmp -> /private/tmp) or user home paths that are symlinks; passing paths like /var/data/current that admins implemented as symlink switches; passing socket or device files that are symlinks into /proc or /run.","solutions":["Resolve the symlink first and pass the real path: use filepath.EvalSymlinks(cleanSource) and pass the resolved result to CopyToVolume.","If symlink following is intended, copy the target content to a real directory (e.g. cp -rL) and use that directory as the source.","If the symlink itself is the artifact to store, archive it manually and load it into the volume by other means instead of CopyToVolume."],"exampleFix":"// before\nerr := dockerutil.CopyToVolume(ctx, \"/tmp/mydata\", volumeName)\n// after\nrealPath, err := filepath.EvalSymlinks(\"/tmp/mydata\")\nif err != nil { return err }\nerr = dockerutil.CopyToVolume(ctx, realPath, volumeName)","handlingStrategy":"validation","validationCode":"import \"path/filepath\"\n\nfunc isSymlink(p string) bool {\n\tfi, err := os.Lstat(p)\n\treturn err == nil && fi.Mode()&os.ModeSymlink != 0\n}\n\nfunc resolveSource(p string) (string, error) {\n\tif isSymlink(p) {\n\t\treturn filepath.EvalSymlinks(p)\n\t}\n\treturn p, nil\n}\n\nreal, err := resolveSource(source)\nif err != nil { return err }\nerr = dockerutil.CopyToVolume(ctx, real, volume)","typeGuard":"func isSymlinkPath(p string) bool {\n\tfi, err := os.Lstat(p)\n\treturn err == nil && fi.Mode()&os.ModeSymlink != 0\n}","tryCatchPattern":"if _, err := dockerutil.CopyToVolume(ctx, src, vol); err != nil {\n\tif strings.Contains(err.Error(), \"source is symlink\") {\n\t\treal, rerr := filepath.EvalSymlinks(src)\n\t\tif rerr != nil { return rerr }\n\t\treturn dockerutil.CopyToVolume(ctx, real, vol)\n\t}\n\treturn err\n}","preventionTips":["Run filepath.EvalSymlinks on user-supplied paths before passing them to CopyToVolume","Reject or resolve symlinks early in any path-ingestion pipeline","Watch for platform symlinks like /tmp -> /private/tmp on macOS","Add a preflight Lstat check in wrappers around CopyToVolume"],"tags":["docker","volumes","symlink","filesystem"],"backgroundTag":"symlinked-source-path","analyzedSha":"81940d17fa112cc678e32209214bcb2355cb3004","analyzedAt":"2026-08-31T23:06:12.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}