{"record":{"id":"4fa85335a8da1d13","repo":"cli/cli","slug":"file-contains-terminal-escape-sequences-use-all","errorCode":null,"errorMessage":"file contains terminal escape sequences; use --allow-escape-sequences to read anyway","messagePattern":"file contains terminal escape sequences; use --allow-escape-sequences to read anyway","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/cmd/repo/read-file/read_file.go","lineNumber":199,"sourceCode":"\t// read-file does its own escape-sequence guarding below, so it writes raw\n\t// bytes through ContentOut in passthrough mode. Leaving sanitization on\n\t// would corrupt binary files and strip the escapes that\n\t// --allow-escape-sequences explicitly allows.\n\topts.IO.SetContentSanitization(false)\n\n\tif mime, ok := iostreams.BinaryContentType(file.Content); ok {\n\t\tif opts.IO.IsStdoutTTY() {\n\t\t\treturn fmt.Errorf(\"binary file (%s, %s); use --output to save to a file or pipe stdout\",\n\t\t\t\tmime, text.FormatSize(int64(file.Size)))\n\t\t}\n\t\t_, err = opts.IO.ContentOut.Write(file.Content)\n\t\treturn err\n\t}\n\n\t// Refuse terminal escape sequences unless --allow-escape-sequences, in both TTY and non-TTY modes,\n\t// so a malicious file cannot manipulate a downstream terminal.\n\tif !opts.AllowEscapeSequences && iostreams.ContainsEscapeSequence(file.Content) {\n\t\treturn errors.New(\"file contains terminal escape sequences; use --allow-escape-sequences to read anyway\")\n\t}\n\n\tif opts.IO.IsStdoutTTY() {\n\t\tif err := opts.IO.StartPager(); err != nil {\n\t\t\tfmt.Fprintf(opts.IO.ErrOut, \"error starting pager: %v\\n\", err)\n\t\t}\n\t\tdefer opts.IO.StopPager()\n\t}\n\n\t_, err = opts.IO.ContentOut.Write(file.Content)\n\treturn err\n}\n\n// loadContent fetches the raw file bytes when the Contents API did not return them inline.\n// The API only omits inline content for large files, which it marks with a \"none\" encoding;\n// everything else (including empty files) comes back base64-encoded, so there is nothing to fetch.\nfunc loadContent(httpClient *http.Client, repo ghrepo.Interface, file *repoFile, ref string) error {\n\tif file.Encoding != \"none\" {","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/cli/cli/blob/0eeec0b92edbe70199f9768522f831d3534f41ad/pkg/cmd/repo/read-file/read_file.go#L181-L217","documentation":"Terminal-safety guard in `gh repo read-file`: before writing fetched file content to output, the bytes are scanned with iostreams.ContainsEscapeSequence, and if any terminal escape sequences are present the write is refused unless --allow-escape-sequences was passed. Unlike the release-download guard this applies in BOTH TTY and non-TTY modes, because even piped output typically ends up in some downstream terminal, and a malicious repo file could otherwise inject ANSI/OSC sequences.","triggerScenarios":"Reading a file from a repository whose bytes contain ESC (0x1b) followed by [ or ] sequences: files with embedded ANSI colors, crafted malicious repo content, or binary-ish text files that happen to contain 0x1b. Applies to both `gh repo read-file owner/repo/file` and programmatic use.","commonSituations":"Reading a repo-hosted .log, .txt, or dotfile with color codes; CI that cats repo files through gh; security-conscious teams scanning untrusted repos. The comment in the source explicitly states the refusal covers non-TTY mode too.","solutions":["If you trust the file, opt in: gh repo read-file owner/repo/FILE --allow-escape-sequences","Otherwise save to a file instead of stdout with --output, then inspect with a tool that renders escapes safely","Scan the file content for 0x1b bytes first if provenance is unknown"],"exampleFix":"# before\ngh repo read-file org/repo/build.log\n# after\ngh repo read-file org/repo/build.log --allow-escape-sequences","handlingStrategy":"validation","validationCode":"content := fetchFile(owner, repo, path)\nif !opts.AllowEscapeSequences && iostreams.ContainsEscapeSequence(content) {\n    return errors.New(\"file contains escape sequences; pass --allow-escape-sequences or --output FILE\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"terminal escape sequences\") {\n    if trusted {\n        err = rerunWithFlag(\"--allow-escape-sequences\")\n    } else {\n        err = rerunWithOutput(tmpFile) // inspect safely\n    }\n}","preventionTips":["Use --output FILE when reading untrusted repo files, then inspect offline","Reserve --allow-escape-sequences for files you authored or audited","Treat escape-sequence hits as a security signal when browsing unknown repos"],"tags":["read-file","security","terminal-safety","escape-sequences","repo"],"backgroundTag":null,"analyzedSha":"0eeec0b92edbe70199f9768522f831d3534f41ad","analyzedAt":"2026-08-15T12:31:05.478Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}