{"record":{"id":"f157af1f8c9cd152","repo":"gastownhall/beads","slug":"invalid-file-path-directory-traversal-not-allowed","errorCode":null,"errorMessage":"invalid file path: directory traversal not allowed","messagePattern":"invalid file path: directory traversal not allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/markdown.go","lineNumber":113,"sourceCode":"\t\tissue.AcceptanceCriteria = content\n\tcase \"assignee\":\n\t\tissue.Assignee = strings.TrimSpace(content)\n\tcase \"labels\":\n\t\tissue.Labels = parseLabels(content)\n\tcase \"dependencies\", \"deps\":\n\t\tissue.Dependencies = parseDependencies(content)\n\t}\n}\n\n// validateMarkdownPath validates and cleans a markdown file path to prevent security issues.\n// It checks for directory traversal attempts and ensures the file is a markdown file.\nfunc validateMarkdownPath(path string) (string, error) {\n\t// Clean the path\n\tcleanPath := filepath.Clean(path)\n\n\t// Prevent directory traversal\n\tif strings.Contains(cleanPath, \"..\") {\n\t\treturn \"\", fmt.Errorf(\"invalid file path: directory traversal not allowed\")\n\t}\n\n\t// Ensure it's a markdown file\n\text := strings.ToLower(filepath.Ext(cleanPath))\n\tif ext != \".md\" && ext != \".markdown\" {\n\t\treturn \"\", fmt.Errorf(\"invalid file type: only .md and .markdown files are supported\")\n\t}\n\n\t// Check file exists and is not a directory\n\tinfo, err := os.Stat(cleanPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"cannot access file: %w\", err)\n\t}\n\tif info.IsDir() {\n\t\treturn \"\", fmt.Errorf(\"path is a directory, not a file\")\n\t}\n\n\treturn cleanPath, nil","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/markdown.go#L95-L131","documentation":"validateMarkdownPath cleans the user-supplied file path and rejects it if the cleaned path still contains \"..\", since that indicates directory traversal. This guards the markdown import path (parseMarkdownFile) from reading files outside the intended workspace via paths like `../../etc/passwd`.","triggerScenarios":"Calling bd's markdown import (e.g. `bd create -i file.md` style flows that call parseMarkdownFile) with a path containing `..`, such as `../notes.md`, `a/../../x.md`, or an absolute path whose cleaned form contains `..`.","commonSituations":"Scripting imports from sibling directories with relative paths; user-supplied file arguments interpolated into commands; tests passing traversal-style paths.","solutions":["Pass a path without `..` — use a path relative to the current directory or an absolute path pointing directly at the file","cd into the directory containing the markdown file and use a plain filename","Resolve/symlink the file into the working directory first"],"exampleFix":"// before\nparseMarkdownFile(\"../notes/tickets.md\")\n// after\nparseMarkdownFile(\"/home/me/notes/tickets.md\")   // or cd to the notes dir and use \"tickets.md\"","handlingStrategy":"validation","validationCode":"func safePath(p string) error {\n\tc := filepath.Clean(p)\n\tif strings.Contains(c, \"..\") {\n\t\treturn fmt.Errorf(\"traversal not allowed: %s\", p)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass absolute paths without .. segments","cd into the file's directory and use plain filenames","Resolve user-supplied paths against a fixed base before import"],"tags":["path-validation","security","cli"],"backgroundTag":"directory-traversal-blocked","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}