{"record":{"id":"49f53c0b6a427bcf","repo":"cli/cli","slug":"the-asset-contains-terminal-escape-sequences-use","errorCode":null,"errorMessage":"the asset contains terminal escape sequences; use `--output` to save it to a file, or pass --allow-escape-sequences to output it anyway","messagePattern":"the asset contains terminal escape sequences; use `--output` to save it to a file, or pass --allow-escape-sequences to output it anyway","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/cmd/release/download/download.go","lineNumber":427,"sourceCode":"\t\t\t)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Copy writes the data from r into a file specified by name.\nfunc (w destinationWriter) Copy(name string, r io.Reader) (copyErr error) {\n\tfp := w.makePath(name)\n\tif fp == \"-\" {\n\t\tif w.allowEscapes {\n\t\t\t_, copyErr = io.Copy(w.stdout, r)\n\t\t\treturn\n\t\t}\n\t\tcopyErr = iostreams.CopyGuardedContent(w.stdout, r, w.isTTY)\n\t\tif binErr, ok := errors.AsType[iostreams.BinaryTerminalError](copyErr); ok {\n\t\t\tcopyErr = fmt.Errorf(\"%w; use `--output` to save it to a file, or pass --allow-escape-sequences to output it anyway\", binErr)\n\t\t} else if errors.Is(copyErr, iostreams.ErrEscapeSequence) {\n\t\t\tcopyErr = errors.New(\"the asset contains terminal escape sequences; use `--output` to save it to a file, or pass --allow-escape-sequences to output it anyway\")\n\t\t}\n\t\treturn\n\t}\n\tif copyErr = w.check(fp); copyErr != nil {\n\t\treturn\n\t}\n\n\tif dir := filepath.Dir(fp); dir != \".\" {\n\t\tif copyErr = os.MkdirAll(dir, 0755); copyErr != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar f *os.File\n\tif f, copyErr = os.OpenFile(fp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); copyErr != nil {\n\t\treturn\n\t}\n","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/cli/cli/blob/0eeec0b92edbe70199f9768522f831d3534f41ad/pkg/cmd/release/download/download.go#L409-L445","documentation":"Terminal-safety guard when a downloaded asset is written to stdout ('-'): the content is scanned by iostreams.CopyGuardedContent, and if it contains terminal escape sequences (ANSI CSI sequences) the write is refused unless --allow-escape-sequences was passed. A malicious or accidentally escape-laden file could otherwise manipulate the terminal (title injection, cursor hijacking, even command execution via OSC 52 in some emulators).","triggerScenarios":"gh release download <tag> -O - (or piping to stdout) where the asset bytes contain escape sequences: log files with ANSI colors embedded, crafted malicious files, or test fixtures containing raw \\x1b[ sequences.","commonSituations":"CI pipelines piping release logs to stdout; downloading a colorized build log artifact; security-hardened environments where the guard is intentionally strict. The sibling branch wraps BinaryTerminalError the same way for binary content on a TTY.","solutions":["Save to a file instead: -O asset.log or --output asset.log","If the content is trusted, opt in explicitly: --allow-escape-sequences","Inspect the asset first (download to file, grep for escape bytes) to confirm it is not malicious"],"exampleFix":"# before\ngh release download v1 -O -   # asset.log contains ANSI escapes\n# after\ngh release download v1 -O asset.log","handlingStrategy":"validation","validationCode":"if stdoutDest && !allowEscapes {\n    // download to a temp file, scan, then decide\n    tmp, _ := os.CreateTemp(\"\", \"asset-\")\n    defer os.Remove(tmp.Name())\n    copyTo(tmp)\n    if iostreams.ContainsEscapeSequence(content) { return errors.New(\"refusing untrusted stdout\") }\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, iostreams.ErrEscapeSequence) {\n    // either re-run with --output FILE or surface a trust decision to the user\n}","preventionTips":["Default to -O <file> in scripts; reserve stdout piping for trusted artifacts","Only pass --allow-escape-sequences for artifacts whose provenance you control","Scan logs/artifacts for ESC bytes (grep -P '\\x1b') in CI before displaying them"],"tags":["release","download","security","terminal-safety","escape-sequences"],"backgroundTag":null,"analyzedSha":"0eeec0b92edbe70199f9768522f831d3534f41ad","analyzedAt":"2026-08-15T12:31:05.478Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}