{"record":{"id":"9793e1c78d3e571f","repo":"multica-ai/multica","slug":"s-path-q-resolves-outside-the-current-working","errorCode":null,"errorMessage":"--%s path %q resolves outside the current working directory; write agent temp files inside the task workdir (e.g. ./%s.md) rather than machine-shared paths like /tmp, where another run's stale file can be read by mistake. Pass --allow-external-file to override.","messagePattern":"--(.+?) path %q resolves outside the current working directory; write agent temp files inside the task workdir \\(e\\.g\\. \\./(.+?)\\.md\\) rather than machine-shared paths like /tmp, where another run's stale file can be read by mistake\\. Pass --allow-external-file to override\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_issue.go","lineNumber":112,"sourceCode":"//\n// Agent task workdirs are isolated per profile and per task; machine-shared\n// scratch paths like /tmp are not. MUL-4252 traced a cross-environment context\n// leak to exactly this gap: a quick-create run wrote its description to a fixed\n// /tmp/desc.md, the write silently failed because a *different* environment's\n// run had left a stale file there minutes earlier, and --description-file then\n// fed that stale content into the new issue. Requiring the file to live under\n// the workdir turns \"silently read another run's file\" into a loud command\n// failure — an \"incorrect content\" bug becomes a \"command errored\" bug.\nfunc ensureFileFlagWithinWorkdir(cmd *cobra.Command, fileFlag, flagName, filePath string) error {\n\tif allow, _ := cmd.Flags().GetBool(\"allow-external-file\"); allow {\n\t\treturn nil\n\t}\n\twithin, err := fileWithinWorkingDir(filePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"resolve --%s path %q: %w\", fileFlag, filePath, err)\n\t}\n\tif !within {\n\t\treturn fmt.Errorf(\n\t\t\t\"--%s path %q resolves outside the current working directory; \"+\n\t\t\t\t\"write agent temp files inside the task workdir (e.g. ./%s.md) rather than machine-shared \"+\n\t\t\t\t\"paths like /tmp, where another run's stale file can be read by mistake. \"+\n\t\t\t\t\"Pass --allow-external-file to override.\",\n\t\t\tfileFlag, filePath, flagName)\n\t}\n\treturn nil\n}\n\n// fileWithinWorkingDir reports whether filePath resolves to a location inside\n// the process working directory. Both sides are symlink-resolved so aliased\n// roots (e.g. macOS /tmp -> /private/tmp) and symlinks planted inside the\n// workdir fail closed. A path that does not exist yet is judged on its cleaned\n// absolute form so the caller's os.ReadFile still surfaces the real not-found\n// error afterwards.\nfunc fileWithinWorkingDir(filePath string) (bool, error) {\n\tcwd, err := os.Getwd()\n\tif err != nil {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_issue.go#L94-L130","documentation":"A file-content flag (--description-file, --content-file, etc.) points to a path that resolves outside the process working directory. The CLI enforces this to prevent a stale-file content leak: an earlier incident had one run silently read a /tmp file written by a different run. The check is symlink-aware on both sides, so aliasing a path into the workdir via symlink does not bypass it.","triggerScenarios":"Passing an absolute path like /tmp/desc.md, a relative path that climbs out of the workdir (../../shared/desc.md), or a workdir symlink pointing to an outside location — unless --allow-external-file is set. fileWithinWorkingDir resolves symlinks on both the file and the working directory, so macOS /tmp -> /private/tmp style aliases are still detected.","commonSituations":"Agents/scripts writing scratch files to /tmp or other machine-shared dirs and feeding them to the CLI; CI jobs sharing a temp dir between parallel runs; a symlink inside the repo pointing at a home-directory file.","solutions":["Write the temp file inside the current working directory (e.g. ./desc.md) as the error message suggests, then re-run.","If the outside location is intentional and you accept the stale-file risk, add --allow-external-file to the command.","If you expected the path to be inside the workdir, check for symlinks (realpath <path>) — the guard resolves them, so the physical location is what counts.","Verify the process is running from the directory you think (pwd), since the boundary is the CWD, not the repo root."],"exampleFix":"# before\nprintf 'content' > /tmp/desc.md\nmultica issue create --title T --description-file /tmp/desc.md\n# after\nprintf 'content' > ./desc.md\nmultica issue create --title T --description-file ./desc.md","handlingStrategy":"validation","validationCode":"# ensure the file is physically inside the CWD (symlinks resolved)\ncase \"$(realpath \"$DESC_FILE\")\" in \"$(realpath .)\"/*) ;; *) echo \"file outside workdir\" >&2; exit 1;; esac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write agent scratch files into the task workdir (./name.md), never /tmp.","Treat --allow-external-file as an explicit, audited exception — not a default in scripts.","Remember the boundary is the process CWD: run the CLI from the directory containing the files."],"tags":["cli","security","filesystem","workdir-guard"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}