AI REVIEW: THE AUTOMATED CHECKS

Written by AI. Held to an unusually strict test bar.

secure-terminal is AI-assisted software. Precisely because a machine wrote it, the security claims are not asked to rest on trust: they rest on a large, automated, adversarial test suite and separate analysis passes that run on every change. This page lists exactly what is checked, so you can read the tests, not just the marketing. Every claim below is something you can verify in the code.

1. The adversarial corpus: real, disclosed attacks

The core of the audit is the terminal-poc-corpus: 22 proofs-of-concept drawn from actual, publicly-disclosed terminal vulnerabilities - answerback injection, DECRQSS and device-status reflection, bracketed-paste bypass, charset-shift deception, cursor-addressing spoofs, homoglyph and Trojan-Source text, iTerm2 title-report injection, and more. Each carries a machine assertion that secure-terminal neutralises it. That corpus is what proves the guarantees; the conformance suites only confirm ordinary programs still render.

Because the corpus stores real attack payloads, it is handled carefully - see the corpus SAFETY notes for the full handling. Two properties matter most:

Hex-encoded. Each payload is stored as hexadecimal in a payload.hex file, not as raw bytes, so browsing or grepping the repository can never accidentally feed a live escape sequence to your own terminal or a code viewer. It is decoded only at run time.

Canary-forked. Each attack is paired with a variant that, on a vulnerable terminal, would write a known "canary" marker file. The harness runs it and checks for the marker, so it can tell "the terminal actively neutralised this" apart from "the test silently did nothing" - the test proves the attack would have fired.

2. A security invariant over the whole spec surface

Beyond the curated attacks, the conformance harness feeds the entire reflection-class spec surface - 387 escape sequences - to secure-terminal in CLI mode and checks three invariants on every one. These are the query and report sequences a terminal historically answers, and answering them is the "output becomes input" bug class; each is documented in the XTerm Control Sequences reference:

  • the primary, secondary and tertiary device-attribute queries (DA1/DA2/DA3);
  • DECRQSS (request a setting the program just set), and the XTVERSION and XTGETTCAP name/version and terminfo queries;
  • the cursor-position and device-status reports (DSR/CPR), and ENQ answerback;
  • the window-size/position and palette/colour queries.

The class, and why answering any of them is dangerous, is laid out in David Leadbeater's 2023 terminal-security review. On each sequence the harness checks:

i. Nothing is written back to the pty. A vulnerable terminal answers a query by writing its reply onto the same channel - which is the program's keyboard. secure-terminal must write zero bytes back, for every query. This is the whole "output becomes input" attack class, closed and asserted.

ii. Nothing non-ASCII is smuggled to the screen. The rendered text may contain only printable ASCII plus tab, newline, and the documented line-local cursor controls (backspace and carriage return, plus the effect of CSI C/D/G/K, all clamped to the line being written). Any other control byte, or any codepoint above 0x7e (the invisible / bidi / homoglyph classes), is a violation.

iii. Nothing crashes. Every sequence must render in bounded time without an exception, including deliberately malformed and over-long ones.

The harness checks itself, too. A positive control feeds a deliberately-vulnerable result and asserts the check FLAGS it; a negative control runs the same predicate over a known-bad terminal to prove the check can actually detect a failure. And a dedicated check asserts that CLI mode never even instantiates the pyte screen engine - so there is no VT state machine to attack in the default mode. A test that cannot fail proves nothing; these can.

3. Reference-parser self-tests

TUI mode renders through a confined pyte screen model. The audit runs pyte's own test suite at the reviewed pin, and cross-checks against libvterm, so the engine secure-terminal relies on is held to its own correctness bar. The public conformance suites (esctest2, pyte, libvterm, vttest) are tracked not to pass them - CLI mode "fails" them by design - but as a corpus of every sequence a real program might emit. Full detail on the compatibility page.

4. Unit, GUI, property and fuzz tests

The application itself carries a large suite that runs in CI on every change, shipped as packages in dist-ai.

SuiteWhat it checks
Core sanitizer (test_secure_terminal)~336 assertions over the Qt-free sanitizer: escape stripping, the four unicode display modes, paste sanitisation, bell detection, the render invariants.
Widget / GUI (test_widget)~626 assertions driving the real Qt widget headless: line editing, scrollback, the paste warning, caret handling - and the character-inspect copy guard that asserts the popup copies the \uXXXX escape and never the raw glyph.
Corpus runner (test_corpus)Runs the dangerous corpus, an every-codepoint sweep over all of Unicode, the Trojan-Source techniques and the git-diffs-lie fixtures against the shipped code, so these attacks gate the package, not just a standalone harness.
Property + fuzz (test_fuzz, fuzz_secure_terminal)Hypothesis property tests (idempotency, ASCII-only output, box-to-underscore export) plus a randomized fuzzer that throws adversarial input at the parse/render path and asserts no crash and every invariant, printing the seed on failure.
Coverage-guided fuzzing (ClusterFuzzLite + Atheris)Seven in-tree fuzz harnesses (the line-mode editor, the strip renderer, the paste sanitiser and classifier, the safe-colour SGR parser, the single-instance IPC frame reassembler, and the settings/session parsers) run under the OSS-Fuzz engine on every PR that touches the parse path, via local-python-fuzz.yml.
AppArmor (secure-terminal-tests-apparmor)Confirms the shipped AppArmor profile loads and confines the application (defence in depth around the memory-safe core).

Coverage. A continuous-integration ratchet gate enforces 100% line coverage on every module of the package - the sanitizer, CLI wrapper, command-hook protocol, IPC framing, session persistence, settings, and the dialog/terminal/main GUI - so a line the tests stop reaching fails the build. Every module is gated, with no un-gated glue left, so whole-package line coverage is 100% (re-verified 2026-08-12).

5. Static analysis and continuous scanners

Alongside the tests, several static analysers run on the repository. Each is a committed GitHub Actions workflow.

ScannerWhat it looks forRuns
BanditCommon Python security anti-patterns (unsafe subprocess, eval, temp-file races, weak crypto).On every change (consumer-bandit.yml).
CodeQL (Python)Dataflow / taint analysis over the Python code - untrusted input reaching a sensitive sink.On every change (consumer-codeql-python.yml).
CodeQL (Actions)The same analysis applied to the GitHub Actions workflows themselves (injection, unpinned actions).On every change (consumer-codeql-actions.yml).
CoverityDeeper interprocedural static analysis.Active - weekly scheduled scan (consumer-coverity.yml); findings land on the Coverity dashboard.

6. AI review by other models

Because the code is AI-authored, it is also AI-reviewed - by different models than wrote it, with fresh context, as a second opinion. This is not an independent third-party audit; it is a different tool looking for defects the authoring model missed. Unlike the checks above, this is run on demand (before a change lands), not on a schedule:

Codex and CodeRabbit review the diff for logic, design and security defects; a fresh-context Claude reviewer does a final local sweep. Each finding is then reconciled individually - verified against the code, applied if real, dropped with a stated reason if not - rather than applied blindly, so the reviewers are advisors, not an autopilot. Real defects caught this way are fixed before the change lands.

7. A live differential regression test

An opt-in test (terminal-resilience-tests) feeds the crafted hostile log to secure-terminal and asserts the neutralisation directly: the output carries no escape byte and no title marker, on every run. That is the part that protects you - a continuous guard that the safe behaviour has not regressed.

The same test also feeds the payload to a real traditional emulator and checks its window title is hijacked. That is not a claim that benefits you; it is a positive control - if a known-vulnerable terminal is somehow not hijacked, the harness itself is broken and the secure-terminal half would be meaningless. It is the automated version of the comparison, and you can reproduce it yourself.