{"record":{"id":"2d5a5977833183be","repo":"vitessio/vitess","slug":"failed-to-parse-backup-path-q-w","errorCode":null,"errorMessage":"failed to parse backup path %q: %w","messagePattern":"failed to parse backup path %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/filebackupstorage/file.go","lineNumber":162,"sourceCode":"\tstat := fbh.fbs.params.Stats.Scope(stats.Operation(\"File:Read\"))\n\treturn ioutil.NewMeteredReadCloser(f, stat.TimedIncrementBytes), nil\n}\n\n// FileBackupStorage implements BackupStorage for local file system.\ntype FileBackupStorage struct {\n\tparams backupstorage.Params\n}\n\nfunc newFileBackupStorage(params backupstorage.Params) *FileBackupStorage {\n\treturn &FileBackupStorage{params}\n}\n\n// ListBackups is part of the BackupStorage interface\nfunc (fbs *FileBackupStorage) ListBackups(ctx context.Context, dir string) ([]backupstorage.BackupHandle, error) {\n\t// Check dir is not a directory traversal.\n\tpath, err := fileutil.SafePathJoin(FileBackupStorageRoot, dir)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse backup path %q: %w\", path, err)\n\t}\n\n\tfi, err := os.ReadDir(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tresult := make([]backupstorage.BackupHandle, 0, len(fi))\n\tfor _, info := range fi {\n\t\tif !info.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tif info.Name() == \".\" || info.Name() == \"..\" {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/filebackupstorage/file.go#L144-L180","documentation":"ListBackups on FileBackupStorage first validates the requested directory with fileutil.SafePathJoin to prevent path traversal; if the joined path is not safely under FileBackupStorageRoot, this error is returned wrapping the underlying reason. The %q prints the (possibly empty) path value alongside the cause.","triggerScenarios":"Calling ListBackups with a dir containing '..' or absolute-path components that escape the backup storage root; a dir that SafePathJoin rejects for any other reason.","commonSituations":"Automated scripts interpolating user or keyspace/table input into the backup dir path; path separators mixed ('/' vs OS separator) or a leading '/' making the path absolute; malicious or buggy input attempting traversal.","solutions":["Pass a relative directory path that resolves strictly inside FileBackupStorageRoot.","Strip or normalize '..' segments and leading slashes from user-supplied dir values before calling.","Inspect the wrapped error from SafePathJoin to see which rule the path violated."],"exampleFix":"// before\nfbs.ListBackups(ctx, \"/etc\")\n// after\nfbs.ListBackups(ctx, \"keyspace-shard-name\")","handlingStrategy":"validation","validationCode":"func safeBackupDir(dir string) bool {\n\treturn dir != \"\" && !strings.Contains(dir, \"..\") && !filepath.IsAbs(dir)\n}\nif !safeBackupDir(userDir) { return errors.New(\"invalid backup dir\") }","typeGuard":null,"tryCatchPattern":"handles, err := fbs.ListBackups(ctx, dir)\nif err != nil {\n\treturn fmt.Errorf(\"list backups for %q: %w\", dir, err)\n}","preventionTips":["Never pass raw user input as backup dir; build from keyspace/shard identifiers","Keep dir paths relative and slash-consistent","Add unit tests for traversal attempts ('..', absolute paths) in tooling"],"tags":["backup-storage","path-traversal","security"],"backgroundTag":"path-traversal-rejected","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}