{"record":{"id":"e714fd46f05eef47","repo":"larksuite/cli","slug":"unsafe-output-dir","errorCode":null,"errorMessage":"unsafe --output-dir","messagePattern":"unsafe --output-dir","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/event/consume.go","lineNumber":450,"sourceCode":"\tif err != nil {\n\t\tif _, ok := errs.ProblemOf(err); ok {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn \"\", errs.NewAuthenticationError(errs.SubtypeTokenMissing,\n\t\t\t\"resolve tenant access token: %s\", err).WithCause(err)\n\t}\n\tif result == nil || result.Token == \"\" {\n\t\treturn \"\", errs.NewAuthenticationError(errs.SubtypeTokenMissing,\n\t\t\t\"no tenant access token available for app %s\", appID).\n\t\t\tWithHint(\"check that app_secret is configured for this distribution\")\n\t}\n\treturn result.Token, nil\n}\n\n// Sentinels for errors.Is checks; call sites wrap them as typed ValidationError causes.\nvar (\n\terrInvalidParamFormat = errors.New(\"invalid --param format\") //nolint:forbidigo // sentinel, typed at call sites\n\terrOutputDirUnsafe    = errors.New(\"unsafe --output-dir\")    //nolint:forbidigo // sentinel, typed at call sites\n)\n\nfunc parseParams(raw []string) (map[string]string, error) {\n\tm := make(map[string]string)\n\tfor _, kv := range raw {\n\t\tk, v, ok := strings.Cut(kv, \"=\")\n\t\tif !ok || k == \"\" {\n\t\t\treturn nil, errs.NewValidationError(errs.SubtypeInvalidArgument,\n\t\t\t\t\"%s %q: expected key=value\", errInvalidParamFormat, kv).\n\t\t\t\tWithParam(\"--param\").\n\t\t\t\tWithCause(errInvalidParamFormat)\n\t\t}\n\t\tm[k] = v\n\t}\n\treturn m, nil\n}\n\n// watchStdinEOF drains r until EOF, writes a diagnostic, then cancels; only safe in non-TTY mode.","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/cmd/event/consume.go#L432-L468","documentation":"errOutputDirUnsafe is a sentinel error for the --output-dir flag in cmd/event/consume.go. sanitizeOutputDir rejects directories that fail path safety checks (e.g. traversal, invalid paths) and call sites wrap it as a typed errs.ValidationError (SubtypeInvalidArgument, param --output-dir) that includes the underlying reason.","triggerScenarios":"Running event consume with --output-dir pointing to an unsafe path such as containing '..' traversal, an invalid/absolute path failing validation, or a path rejected by the path-safety check in sanitizeOutputDir.","commonSituations":"Scripts interpolating user input into the flag; relative paths that resolve outside the allowed root; copy-pasted Windows-style paths on POSIX hosts; CI templates with placeholder traversal segments.","solutions":["Provide a simple, safe directory path without '..' or traversal segments (e.g. ./out or /tmp/events).","Create the directory first if required and confirm you have write permission.","Read the wrapped %s reason in the error to see which specific check failed.","In scripts, sanitize the path (or use a fixed workspace-relative directory) before passing it."],"exampleFix":"// before\nlark event consume --output-dir ../../etc\n// after\nlark event consume --output-dir ./out","handlingStrategy":"validation","validationCode":"// shell pre-check before invoking the CLI\ncase \"$outdir\" in\n  *..*|\"\"|/) echo \"unsafe --output-dir: $outdir\"; exit 1 ;;\nesac\nmkdir -p \"$outdir\" 2>/dev/null || { echo \"cannot create $outdir\"; exit 1; }","typeGuard":"func looksSafeOutputDir(dir string) bool {\n\tif dir == \"\" || strings.Contains(dir, \"..\") {\n\t\treturn false\n\t}\n\treturn filepath.IsAbs(dir) || strings.HasPrefix(dir, \"./\") || !strings.ContainsRune(dir, ':')\n}","tryCatchPattern":"// Go caller of sanitizeOutputDir\nsafe, err := sanitizeOutputDir(dir)\nif err != nil {\n\tif errors.Is(err, errOutputDirUnsafe) {\n\t\t// fall back to a default workspace-relative directory\n\t\tsafe, err = sanitizeOutputDir(\"./out\")\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n}","preventionTips":["Use fixed workspace-relative output directories in scripts/CI.","Never interpolate raw user input directly into --output-dir.","Create the directory beforehand and confirm write permission.","Avoid '..' and platform-specific path quirks in flag values."],"tags":["go","cli","path-safety"],"backgroundTag":"unsafe-path-rejected","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"}