larksuite/cli · error

%s contains invalid control characters

Error message

%s contains invalid control characters

What it means

RejectControlChars flags C0 control characters (excluding tab and newline) such as 0x00-0x1F and 0x7F in a user-supplied string. These characters are invisible or terminal-altering and enable spoofing/argument-injection, so the library rejects them at input validation time.

Source

Thrown at internal/charcheck/charcheck.go:18

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

// Package charcheck provides character-level security checks shared across
// path validation (localfileio) and input validation (validate) packages.
// Keeping these checks in one place ensures consistent detection of dangerous
// Unicode and control characters throughout the codebase.
package charcheck

import "fmt"

// RejectControlChars rejects C0 control characters (except \t and \n) and
// dangerous Unicode characters (Bidi overrides, zero-width, line/paragraph
// separators) that enable visual spoofing attacks.
func RejectControlChars(value, flagName string) error {
	for _, r := range value {
		if r != '\t' && r != '\n' && (r < 0x20 || r == 0x7f) {
			return fmt.Errorf("%s contains invalid control characters", flagName)
		}
		if IsDangerousUnicode(r) {
			return fmt.Errorf("%s contains dangerous Unicode characters", flagName)
		}
	}
	return nil
}

// IsDangerousUnicode identifies Unicode code points used for visual spoofing
// attacks. These characters are invisible or alter text direction, allowing
// attackers to make "report.exe" display as "report.txt" (Bidi override) or
// insert hidden content (zero-width characters).
func IsDangerousUnicode(r rune) bool {
	switch {
	case r >= 0x200B && r <= 0x200D: // zero-width space/non-joiner/joiner
		return true
	case r == 0xFEFF: // BOM / ZWNBSP
		return true

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Remove the control characters (keep only printable text plus tab/newline)
  2. Re-encode or re-copy the value from a clean source
  3. Sanitize the string programmatically, stripping runes < 0x20 (except \t, \n) and 0x7F before passing it

Example fix

// before
flag := "report\x1b[31m.txt"
// after
clean := strings.Map(func(r rune) rune {
    if (r != '\t' && r != '\n' && r < 0x20) || r == 0x7f {
        return -1
    }
    return r
}, flag)
Defensive patterns

Strategy: validation

Validate before calling

func hasControlChars(s string) bool {
    for _, r := range s {
        if r != '\t' && r != '\n' && (r < 0x20 || r == 0x7f) {
            return true
        }
    }
    return false
}
// call before invoking the command
if hasControlChars(userValue) { return errors.New("value contains control characters") }

Type guard

func isCleanInput(s string) bool {
    for _, r := range s {
        if r != '\t' && r != '\n' && (r < 0x20 || r == 0x7f) || IsDangerousUnicode(r) {
            return false
        }
    }
    return true
}

Prevention

When it happens

Trigger: Passing a flag value containing e.g. \x00, \x1b (escape sequences), or \r to any validated input path such as LocalInputPath, SafeEnvDirPath, or resolveTargetPath callers.

Common situations: Copying text with hidden control bytes from PDFs or terminals; binary content read as text; shell heredocs adding trailing control chars; paste from Windows CRLF sources introducing stray bytes.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/3864ea9f124ed5eb. Report an issue: GitHub.