larksuite/cli · error
%s contains dangerous Unicode characters
Error message
%s contains dangerous Unicode characters
What it means
RejectControlChars also rejects Unicode code points known to enable visual spoofing: bidirectional overrides, zero-width characters, and line/paragraph separators. A string containing these looks different from what it actually is (e.g. reversed filename extensions), so the library treats them as invalid input.
Source
Thrown at internal/charcheck/charcheck.go:21
// 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
case r >= 0x202A && r <= 0x202E: // Bidi: LRE/RLE/PDF/LRO/RLO
return true
case r >= 0x2028 && r <= 0x2029: // line/paragraph separatorView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove the dangerous Unicode characters from the value
- Retype the value manually in plain ASCII or clean Unicode
- Normalize with a Unicode normalizer and strip bidi/zero-width code points before passing
Example fix
// before name := "report\u202Etxt.exe" // RLO reversal // after name := "report.txt"
Defensive patterns
Strategy: validation
Validate before calling
func hasDangerousUnicode(s string) bool {
for _, r := range s {
if IsDangerousUnicode(r) { return true }
}
return false
}
if hasDangerousUnicode(fileName) { fileName = sanitizeUnicode(fileName) } Type guard
func isUnicodeSafe(s string) bool {
for _, r := range s {
if IsDangerousUnicode(r) { return false }
}
return true
} Prevention
- Normalize user filenames with golang.org/x/text/unicode/norm
- Strip bidi/zero-width code points at ingestion boundaries
- Be extra careful with filenames from untrusted sources (spoofing vector)
When it happens
Trigger: A flag value containing U+202E (RLO), U+200B (zero-width space), U+2028/U+2029, or similar detected by IsDangerousUnicode, on any RejectControlChars-guarded input.
Common situations: Usernames or filenames crafted (or copy-pasted) with invisible/bidi characters; multilingual text with zero-width joiners from social platforms; homograph-spoofed file names.
Related errors
- %s contains invalid control characters
- %s contains dangerous Unicode 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/7d50597ecd00288e.
Report an issue: GitHub.