{"record":{"id":"3e3848b383f9e844","repo":"vxcontrol/pentagi","slug":"file-name-contains-control-characters","errorCode":null,"errorMessage":"file name contains control characters","messagePattern":"file name contains control characters","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"backend/pkg/flowfiles/files.go","lineNumber":167,"sourceCode":"\t\t\treturn \"\", fmt.Errorf(\"invalid path component '%s': %w\", part, err)\n\t\t}\n\t\tparts[i] = cleanPart\n\t}\n\n\treturn path.Join(parts...), nil\n}\n\nfunc validatePathComponent(component string) (string, error) {\n\tcleanName := strings.TrimSpace(component)\n\tif cleanName == \".\" || cleanName == \"..\" || cleanName == \"/\" || cleanName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid file name\")\n\t}\n\tif len(cleanName) > MaxFileNameLength {\n\t\treturn \"\", fmt.Errorf(\"file name is too long\")\n\t}\n\tfor _, r := range cleanName {\n\t\tif r < 0x20 || r == 0x7f {\n\t\t\treturn \"\", fmt.Errorf(\"file name contains control characters\")\n\t\t}\n\t\tswitch r {\n\t\tcase '/', '\\\\', ':', '*', '?', '\"', '<', '>', '|':\n\t\t\treturn \"\", fmt.Errorf(\"file name contains unsupported characters\")\n\t\t}\n\t}\n\n\treturn cleanName, nil\n}\n\nfunc NewFile(info os.FileInfo, sourceDir string) File {\n\treturn NewFileWithPath(info, path.Join(sourceDir, info.Name()))\n}\n\nfunc NewFileWithPath(info os.FileInfo, filePath string) File {\n\treturn File{\n\t\tID:         ID(filePath),\n\t\tName:       info.Name(),","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/flowfiles/files.go#L149-L185","documentation":"validatePathComponent scans each rune and rejects components containing ASCII control characters (bytes < 0x20 or 0x7f DEL), returning 'file name contains control characters'. Control characters are illegal in most filesystems and a common path-injection vector.","triggerScenarios":"SanitizeFileName or SanitizeContainerCachePath with a component containing \\n, \\r, \\t, \\x00, escape bytes, or DEL — e.g. filenames extracted from raw binary data, log lines with embedded newlines, or names built from untrusted terminal output.","commonSituations":"Agent passes a file name copied from terminal output including ANSI escape sequences or a trailing newline; uploads where the multipart filename came from a crafted HTTP client with %0A or %00; paths parsed from binary formats.","solutions":["Strip or reject control characters at the source before calling (e.g. strings.Map replacing r < 0x20 || r == 0x7f).","Ensure filenames from terminal/log parsing are trimmed of newlines and escape sequences.","Treat this as suspicious input: log and reject the request rather than sanitizing silently if it may be an injection attempt."],"exampleFix":"// before\nname, err := flowfiles.SanitizeFileName(\"log\\x1b[31m.txt\")\n// after\ncleaned := strings.Map(func(r rune) rune {\n    if r < 0x20 || r == 0x7f { return -1 }\n    return r\n}, \"log\\x1b[31m.txt\")\nname, err := flowfiles.SanitizeFileName(cleaned)","handlingStrategy":"validation","validationCode":"func hasControlChars(s string) bool {\n    for _, r := range s {\n        if r < 0x20 || r == 0x7f {\n            return true\n        }\n    }\n    return false\n}","typeGuard":"func isPrintableName(s string) bool {\n    for _, r := range s {\n        if r < 0x20 || r == 0x7f {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err != nil {\n    if err.Error() == \"file name contains control characters\" {\n        return fmt.Errorf(\"rejecting name with control characters (possible injection)\")\n    }\n    return err\n}","preventionTips":["Strip newlines/ANSI escapes when extracting names from terminal or log output.","Reject rather than silently clean suspicious control bytes.","Validate names decoded from URLs (watch for %00, %0A, %0D)."],"tags":["go","filename-validation","control-characters","input-validation"],"backgroundTag":"invalid-filename-characters","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}