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 trueView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove the control characters (keep only printable text plus tab/newline)
- Re-encode or re-copy the value from a clean source
- 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
- Sanitize copy-pasted or externally sourced strings before use
- Strip < 0x20 (except \t,\n) and 0x7F in a shared input-normalization helper
- Avoid binary-as-text inputs; decode explicitly first
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
- %s contains dangerous Unicode characters
- local input path must not contain control characters
- set_header: header name must not contain ':', CR, or LF
- set_header: header value must not contain CR or LF
- Invalid column: {column!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/3864ea9f124ed5eb.
Report an issue: GitHub.