vxcontrol/pentagi · error

file name contains control characters

Error message

file name contains control characters

What it means

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.

Source

Thrown at backend/pkg/flowfiles/files.go:167

			return "", fmt.Errorf("invalid path component '%s': %w", part, err)
		}
		parts[i] = cleanPart
	}

	return path.Join(parts...), nil
}

func validatePathComponent(component string) (string, error) {
	cleanName := strings.TrimSpace(component)
	if cleanName == "." || cleanName == ".." || cleanName == "/" || cleanName == "" {
		return "", fmt.Errorf("invalid file name")
	}
	if len(cleanName) > MaxFileNameLength {
		return "", fmt.Errorf("file name is too long")
	}
	for _, r := range cleanName {
		if r < 0x20 || r == 0x7f {
			return "", fmt.Errorf("file name contains control characters")
		}
		switch r {
		case '/', '\\', ':', '*', '?', '"', '<', '>', '|':
			return "", fmt.Errorf("file name contains unsupported characters")
		}
	}

	return cleanName, nil
}

func NewFile(info os.FileInfo, sourceDir string) File {
	return NewFileWithPath(info, path.Join(sourceDir, info.Name()))
}

func NewFileWithPath(info os.FileInfo, filePath string) File {
	return File{
		ID:         ID(filePath),
		Name:       info.Name(),

View on GitHub (pinned to ea665308ba)

Solutions

  1. Strip or reject control characters at the source before calling (e.g. strings.Map replacing r < 0x20 || r == 0x7f).
  2. Ensure filenames from terminal/log parsing are trimmed of newlines and escape sequences.
  3. Treat this as suspicious input: log and reject the request rather than sanitizing silently if it may be an injection attempt.

Example fix

// before
name, err := flowfiles.SanitizeFileName("log\x1b[31m.txt")
// after
cleaned := strings.Map(func(r rune) rune {
    if r < 0x20 || r == 0x7f { return -1 }
    return r
}, "log\x1b[31m.txt")
name, err := flowfiles.SanitizeFileName(cleaned)
Defensive patterns

Strategy: validation

Validate before calling

func hasControlChars(s string) bool {
    for _, r := range s {
        if r < 0x20 || r == 0x7f {
            return true
        }
    }
    return false
}

Type guard

func isPrintableName(s string) bool {
    for _, r := range s {
        if r < 0x20 || r == 0x7f {
            return false
        }
    }
    return true
}

Try / catch

if err != nil {
    if err.Error() == "file name contains control characters" {
        return fmt.Errorf("rejecting name with control characters (possible injection)")
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/3e3848b383f9e844. Report an issue: GitHub.