{"record":{"id":"73f254f30c88c330","repo":"larksuite/cli","slug":"s-q-resolves-outside-the-current-working-directo","errorCode":null,"errorMessage":"%s %q resolves outside the current working directory (hint: a relative path has to stay inside it; give a full path to reach another allowed root)","messagePattern":"(.+?) %q resolves outside the current working directory \\(hint: a relative path has to stay inside it; give a full path to reach another allowed root\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/vfs/localfileio/path.go","lineNumber":217,"sourceCode":"\treturn primary, nil\n}\n\n// checkRelativeStaysInCwd holds a relative path to the working directory even\n// when a wider allow root would accept where it lands. Naming a full path is a\n// deliberate act and the allowlist is the right judge of it; climbing out with\n// \"..\" is not, and the two cannot share one verdict once an allow root is big\n// enough to contain the working directory. A process running under /tmp — CI\n// runners, containers and agent sandboxes commonly do — would otherwise reach\n// a sibling session's files with \"../\", which the allowlist alone reads as\n// still inside /tmp.\nfunc checkRelativeStaysInCwd(flagName, raw, resolved, cwd string) error {\n\tif filepath.IsAbs(raw) || raw == \"~\" || strings.HasPrefix(raw, \"~/\") {\n\t\treturn nil\n\t}\n\tif matchResolved(resolved, newPolicyEntry(\"the current working directory\", cwd)) {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"%s %q resolves outside the current working directory \"+\n\t\t\"(hint: a relative path has to stay inside it; give a full path to reach another allowed root)\",\n\t\tflagName, raw)\n}\n\n// interpretations returns every location this platform could open the argument\n// at, most-intended first. They differ only for a leading \"~\": the first entry\n// expands it to the home directory (what a caller using the returned path\n// gets), the second keeps it literal (what the OS does with the original\n// string).\nfunc interpretations(raw, cwd string) ([]string, error) {\n\tabs, err := absolutize(raw, cwd)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout := []string{abs}\n\tif raw == \"~\" || strings.HasPrefix(raw, \"~/\") {\n\t\tliteral := filepath.Clean(filepath.Join(cwd, raw))\n\t\tif literal != abs {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/vfs/localfileio/path.go#L199-L235","documentation":"This error enforces the rule that a RELATIVE path passed to `--file`/`--output` must resolve inside the current working directory, even when the resolved location would otherwise be inside a wider allow root (e.g. /tmp). It prevents `../` traversal: a process running under /tmp (CI runners, containers) could otherwise reach sibling sessions' files.","triggerScenarios":"Passing a relative path containing `..` that escapes cwd, e.g. `--file ../other/report.pdf` when cwd is /tmp/work and the target resolves to /tmp/other. Absolute paths and `~/...` paths are exempt.","commonSituations":"Scripts that `cd` into a subdirectory and reference project files via `../`; CI runners whose cwd is inside /tmp; composing commands where the file sits next to (not under) the working directory.","solutions":["Use a relative path that stays under the current working directory (e.g. sub/file.pdf, not ../file.pdf).","Pass a full absolute path to the target file — a deliberate full path is judged by the allowlist.","cd into the directory containing the file before running the command.","Place the file under ~/files, which is an allowed root for full paths."],"exampleFix":"// before (cwd=/tmp/work)\nlark-cli drive upload --file ../shared/report.pdf\n// after\nlark-cli drive upload --file /tmp/shared/report.pdf","handlingStrategy":"validation","validationCode":"// Go: refuse relative paths that climb out of cwd before calling the API\nif !filepath.IsAbs(p) && !strings.HasPrefix(p, \"~\") {\n    abs, _ := filepath.Abs(p)\n    cwd, _ := os.Getwd()\n    if !strings.HasPrefix(abs, cwd+string(filepath.Separator)) {\n        return fmt.Errorf(\"relative path %q must stay inside cwd; pass an absolute path instead\", p)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["cd to the project root before invoking commands with relative file flags.","Use absolute paths whenever the target is not directly under the working directory.","Avoid ../ in generated scripts; compute paths from an explicit base directory.","Place shared input/output files under ~/files or /tmp and reference them with full paths."],"tags":["go","path-traversal","path-validation","vfs"],"backgroundTag":"path-escapes-working-directory","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}