Harnais d'analyse statique de sécurité applicative multi-agents pour les agents de codage IA : cartographie les bases de code, traque les classes de vulnérabilités, enchaîne et vérifie les résultats, et produit des rapports en SARIF, JSON et PDF.
Un harnais de revue de sécurité applicative multi-agents pour Claude Code (et, à terme, d'autres agents IA). Une compétence de routage unique dispatche vers un pipeline complet de sécurité offensive qui cartographie une base de code, traque les vulnérabilités avec une base de connaissances par classe, enchaîne les découvertes en escalades, vérifie l'impact réel, et rapporte vers README / JSON / SARIF / doc / PDF.
Périmètre : ce harnais effectue une analyse statique (revue de code source, traçage de flux de données, construction de PoC/payload) sur du code que vous possédez ou êtes autorisé à tester. Il n'attaque pas de systèmes tiers en production.
security-harness/ # a plugin marketplace └── plugins/security-harness/ ├── skills/ │ ├── sh-router # single entry point - routes any appsec request │ ├── sh-security-review # the pipeline orchestrator (Stages 0-5) │ └── sh-kb-* (15) # per-vuln-class knowledge bases ├── agents/ │ ├── sh-recon # map: Graft graph + stack/SBOM/CVE + attack surface │ ├── sh-hunter # find: source→sink hunting, one per class (parallel) │ ├── sh-chainer # escalate: combine findings into attack chains │ ├── sh-verifier # confirm: offensive + seceng + dev verification + PoC │ └── sh-reporter # deliver: README/JSON/SARIF/HTML/PDF/doc └── references/ # shared contracts (finding schema, SARIF map, state files, rubrics)
### Classes de vulnérabilités couvertes (les compétences `sh-kb-*`)
contrôle d'accès (IDOR/BOLA/élévation de privilèges) · sqli · xss · ssrf · injection (cmd/code/SSTI/LDAP) · auth (session/JWT)
· désérialisation · path-traversal (LFI/RFI) · secrets · csrf · xxe · open-redirect · crypto · race-conditions
· file-upload. Les CVE de dépendances/SBOM sont gérés par l'étape de reconnaissance.
## Installation
Le harness est fourni pour plusieurs agents. Les détails complets du packaging et la checklist
de release sont dans [`docs/DISTRIBUTION.md`](https://github.com/dmdhrumilmistry/security-harness/blob/main/docs/DISTRIBUTION.md).
**Claude Code** - ajoutez ce dépôt comme marketplace de plugins et installez le plugin :```
/plugin marketplace add dmdhrumilmistry/security-harness
/plugin install security-harness
/plugin marketplace add accepte l'un des éléments suivants : un owner/repo GitHub (comme ci-dessus), une URL git complète
(https://github.com/dmdhrumilmistry/security-harness.git), ou un chemin local vers un clone
(par exemple /plugin marketplace add ./security-harness depuis le répertoire contenant votre copie de travail).
Exécutez ensuite /plugin install security-harness et rechargez lorsque cela vous est demandé.
Gemini CLI - une extension native, manifeste à la racine du dépôt :```bash gemini extensions install https://github.com/dmdhrumilmistry/security-harness
**opencode, Codex, ou tout agent [agentskills.io](https://agentskills.io)** - copiez les
skills dans un répertoire de découverte. Codex récupère en outre `AGENTS.md` de lui-même :```bash
git clone https://github.com/dmdhrumilmistry/security-harness
cd security-harness
python3 scripts/sync-agent-skills.py --install agents # ~/.agents/skills
python3 scripts/sync-agent-skills.py --install opencode # ~/.config/opencode/skills
Graft est installé et configuré automatiquement par le pipeline. L'étape 0 exécute npm install -g @nanonets/graft s'il est absent (nécessite Node/npm), puis graft init <target> --no-agents --no-global
pour enregistrer le serveur MCP Graft et les hooks de fraîcheur pour le dépôt cible. Le graphe lui-même (<target>/graft/,
auto-gitignoré) est construit pendant la reconnaissance. Pour pré-installer manuellement : npm install -g @nanonets/graft. La construction
structurelle de Graft est gratuite et ne nécessite aucune clé API ; la passe LLM optionnelle --deep utilise GRAFT_API_KEY /
GRAFT_PROVIDER / GRAFT_MODEL lorsqu'ils sont définis.
Les autres outils sont également auto-installés par l'étape 0 lorsqu'ils sont absents (via le gestionnaire de paquets présent sur la
machine - winget/choco/scoop, brew, apt, npm/pip/go - voir references/tooling-setup.md). Les installations sont
annoncées, privilégient les méthodes sans élévation de privilèges et ne bloquent jamais l'exécution : tout ce qui ne peut pas être installé est simplement
marqué comme indisponible et le pipeline se rabat sur une alternative. L'étape 0 n'installe que ce qui comble un groupe de capacités manquant :
syft · CVE : l'un de grype
(préféré), trivy, ou osv-scannerwkhtmltopdf ou pandoc (pour PDF/DOCX) ; sinon vous obtenez report.html (ou un PDF via Chrome headless).Tous sont optionnels - le pipeline se dégrade gracieusement vers la recherche native + l'analyse des manifestes si aucun ne s'installe.
Invoquez le routeur avec une requête en langage naturel :``` /sh-router full security review of ./api /sh-router find SQLi and IDOR in src/ /sh-router just map this codebase # recon only
Ou appelez directement le pipeline :```
/sh-security-review . classes:sqli,access-control,ssrf depth:deep
/sh-security-review . stage:report # regenerate reports for the latest run
Chaque étape s'exécute sur un modèle adapté à sa charge cognitive, de sorte que les tokens sont dépensés là où la qualité de la découverte en dépend réellement et économisés sur le travail mécanique. C'est le comportement par défaut - aucun argument nécessaire.
| Étape | Modèle par défaut |
|---|---|
| recon | sonnet |
| hunt (par classe) | haiku pour les classes de motifs (secrets, crypto, open-redirect, csrf) · sonnet pour le traçage source→sink (sqli, xss, ssrf, injection, path-traversal, xxe, file-upload, auth) · opus pour les classes de logique profonde (access-control, race-conditions, deserialization) |
| chain | opus |
| verify | opus (le filtre de précision - maintenu robuste) |
| report | haiku |
Remplacer avec l'argument models: (également transmis au routeur) :```
/sh-security-review . # default tiered map above
/sh-security-review . models:max # every stage + hunter on opus (max quality, max cost)
/sh-security-review . models:cheap # aggressive downshift (trades some verify precision)
/sh-security-review . models:verify=opus,hunt=sonnet # per-stage overrides
/sh-security-review . models:report=sonnet,hunt.pattern=sonnet # per-hunter-tier override
Stages : `setup, recon, hunt, chain, verify, report`. Modèles : `opus, sonnet, haiku, inherit`. Pour `hunt`,
un modèle seul aplatit tous les hunters sur celui-ci ; `hunt.pattern` / `hunt.trace` / `hunt.logic` ciblent un seul tier.
D'autres économiseurs de tokens sont intégrés : recon ne génère des hunters que pour les classes ayant une surface d'attaque réelle, les hunters
interrogent le graphe Graft au lieu de lire des fichiers entiers, et `findings.json`/SARIF sont générés par un
script déterministe plutôt que par le modèle.
### Sortie
Tout atterrit sous `<target>/.security-harness/<run-id>/` :
- `recon.md`, `codebase-map.json` - la carte (stack, SBOM, CVE, surface d'attaque).
- `findings.jsonl` → `chains.md` → `verified.jsonl` - l'état de travail (voir `references/state-files.md`).
- `reports/` - `README.md`, `findings.json`, `results.sarif`, `report.html`, `report.pdf` (+ `report.docx`).
Chaque finding publié porte une charge utile, un PoC, le verdict de vérification, les identifiants CWE/OWASP, le CVSS, et une
atténuation au niveau du code.
## Revue de pull request
`sh-pr-review` examine une seule pull request plutôt qu'une base de code entière, publie le
résultat sous forme de commentaires inline **sur la PR elle-même**, et définit un statut de commit `security/pr-review`
que la protection de branche peut appliquer.
**Exécutez-le depuis votre propre machine, sur n'importe quelle PR que vous pouvez lire.** Installez le plugin et demandez :```
review https://github.com/acme/api/pull/128
review PR 42
security review this PR
Collez un lien de PR et il examine cette PR dans ce dépôt, en le clonant d'abord dans un répertoire temporaire, car les hunters lisent les fichiers et pas seulement le patch. Rien n'est écrit dans le dépôt sur lequel vous travaillez.
Passez un simple numéro et il est résolu par rapport au dépôt dans lequel vous vous trouvez actuellement, celui
vers lequel pointe git remote. Ne passez rien et il prend la PR ouverte pour votre branche actuelle.
La phase 7 affiche les résultats et le verdict et demande avant de publier quoi que ce soit - un refus est un résultat normal, et la charge utile reste sur le disque pour que vous puissiez la publier plus tard.
Avant de dépenser la moindre analyse, il vérifie si vous pouvez réellement écrire dans le dépôt cible, afin qu'examiner le projet de quelqu'un d'autre vous indique d'emblée que la publication renverra un 403 plutôt que de le découvrir dix minutes plus tard.
Trois propriétés le rendent utilisable comme barrière de fusion plutôt que comme bruit :
pr_impact
de introduced, aggravated ou pre_existing. Les deux premiers bloquent ; pre_existing
est signalé et ne bloque jamais. Bloquer une fusion à cause de code que l'auteur n'a jamais écrit est la façon
dont une vérification requise finit par être supprimée, donc lorsqu'un hunter hésite entre aggravated et
pre_existing, il doit choisir pre_existing.sh-kb-* utilisent, puis choisit un palier. Le palier 0 (aucun changement pertinent pour la sécurité) ne lance rien du
tout et définit quand même le statut. Le palier 3 exécute le pipeline complet.| Verdict | Statut | Quand |
|---|---|---|
| fail | failure | résultat introduced ou aggravated au niveau ou au-dessus de --fail-on (par défaut medium), confiance >= 80 |
| warn | success | rien d'introduced ou d'aggravated ; résultats préexistants signalés |
| pass | success | aucun résultat, ou triage arrêté au palier 0 |
| error | error | la revue n'a pas pu se terminer |
warn signale success à dessein : un avertissement qui bloque une fusion est un échec avec
des étapes supplémentaires, et les équipes réagissent en supprimant la vérification. error est gardé distinct de
failure afin qu'une exécution cassée ne ressemble jamais à une vulnérabilité qu'elle n'a pas trouvée.
L'événement de revue est toujours COMMENT, jamais REQUEST_CHANGES ni APPROVE. Le statut
de commit est le mécanisme d'application, et c'est celui que lit la protection de branche.
Périmètre : la skill écrit dans la pull request et le statut de commit, et nulle part ailleurs. Elle n'ouvre aucune issue et ne crée rien dans un quelconque tracker externe.
Une PR est examinée une fois par push, donc la seconde revue doit être moins coûteuse que la première, sinon l'outil devient quelque chose que les gens désactivent.
La déduplication a lieu avant la dépense, pas avant la publication. Les empreintes déjà présentes sur la PR sont lues en phase 1 et transmises aux hunters et au vérificateur. Trouver un doublon à la fin signifierait que le modèle le plus coûteux du pipeline avait déjà re-confirmé une conclusion qui était écrite sur la PR depuis le début. Cela ne nécessite aucun cache : l'état vit dans la PR, donc cela fonctionne sur une machine froide et en CI.
Un cache local rend le reste incrémental. sh-review-cache stocke les hachages de fichiers, les résultats et les verdicts de chaque exécution
sous votre répertoire de cache du système d'exploitation (jamais dans le dépôt, puisqu'une
revue inter-dépôts s'exécute dans un clone temporaire qui est supprimé). La revue suivante ne re-chasse que
les fichiers dont le contenu a réellement changé, réutilise les verdicts pour les résultats inchangés, et
réutilise la carte de reconnaissance si rien de ce qu'elle couvre n'a bougé.
Une fusion de branche de base ne coûte rien. Fusionner main dans une branche de PR change le SHA de tête
et rien de ce que l'auteur a écrit, mais un statut de commit est épinglé à un SHA, donc la vérification requise
disparaît silencieusement de la nouvelle tête. Lorsque les fichiers propres de la PR sont identiques octet pour octet
et que le delta de base ne touche rien dont dépendent les résultats, le verdict précédent est
ré-apposé sur le nouveau SHA sans qu'aucun agent ne soit lancé du tout. Cette dernière condition est ce qui
le rend sûr : une fusion de base qui supprime un sanitizer laisse chaque fichier de la PR inchangé tout en
transformant une ligne sûre en ligne exploitable.
L'invalidation est délibérément conservatrice, car une entrée obsolète dans un outil de sécurité ne
le rend pas lent, elle le rend faux. La clé de cache hache chaque base de connaissances sh-kb-*,
donc une mise à jour de KB invalide chaque résultat mis en cache - un « clean » mis en cache ne doit jamais
supprimer le résultat que cette mise à jour était censée attraper. L'identité du modèle, la version de la skill, le contenu
des fichiers et un TTL de 7 jours invalident aussi, et un modèle non spécifié est traité comme un échec de cache.
--no-cache le désactive, --refresh-cache ré-établit la base, et run.md enregistre par phase
ce qui a été lancé, réutilisé et ignoré, afin qu'un cache qui cesse discrètement de fonctionner soit visible
plutôt que supposé.
La revue et le statut de commit sont publiés par défaut. Une revue qui a été calculée et
jamais livrée n'a aidé personne. --confirm rétablit une invite avant la publication, --dry-run
n'envoie rien, --no-status publie la revue mais laisse le statut de commit tranquille.
La publication passe par scripts/sh-pr-post.py plutôt que par des appels API construits à la main, car c'est
une opération multi-étapes avec une queue obligatoire : revue, puis statut, puis reçus, avec
un 422 récupéré en déplaçant le commentaire plutôt qu'en décalant un numéro de ligne. Le script
ne se termine jamais en laissant le statut à pending - s'il ne peut pas publier la revue, il définit quand même
error, disant que l'outillage a échoué plutôt que d'accuser la PR.
Les commentaires en ligne sont réservés aux résultats de medium ou plus avec une confiance >= 80. Les résultats de faible gravité vont dans la section repliée du corps, donc un résultat de faible priorité qui apparaît avec zéro commentaire en ligne est la politique qui fonctionne, pas un échec.
Chaque exécution enregistre ce qu'elle a coûté, afin que « le cache fonctionne » et « les revues sont devenues plus lentes » cessent d'être des questions d'opinion.```bash python3 /scripts/sh-metrics.py path # where records live python3 /scripts/sh-metrics.py report # aggregate, by model python3 /scripts/sh-metrics.py purge --older-than-days 30
Deux fichiers JSONL en ajout seul - `runs.jsonl` (dépôt, PR, niveau, verdict, totaux, les indicateurs que vous
avez passés) et `events.jsonl` (une ligne par phase ou agent : modèle, jetons, durée, résultat,
s'il a été réutilisé depuis le cache). JSONL afin qu'une exécution plantée laisse tout de même des lignes valides au-dessus
du plantage.
| Plateforme | Métriques | Cache |
|---|---|---|
| **Linux / BSD** | `$XDG_DATA_HOME/security-harness/metrics`<br>par défaut `~/.local/share/security-harness/metrics` | `$XDG_CACHE_HOME/security-harness`<br>par défaut `~/.cache/security-harness` |
| macOS | `~/Library/Application Support/security-harness/metrics` | `~/Library/Caches/security-harness` |
| Windows | `%LOCALAPPDATA%\security-harness\metrics` | `%LOCALAPPDATA%\security-harness\cache` |
Linux suit la spécification XDG Base Directory, donc les deux respectent `XDG_DATA_HOME` et
`XDG_CACHE_HOME` lorsqu'ils sont définis et se rabattent sur `~/.local/share` et `~/.cache` lorsqu'ils ne le sont
pas. Remplacez l'un ou l'autre directement avec `SH_METRICS_DIR` et `SH_REVIEW_CACHE_DIR`.
**À propos de `python` vs `python3` :** la plupart des distributions Linux fournissent `python3` et n'ont pas du tout
`python`, donc les exemples ici utilisent `python3`. Les scripts fournis portent un
shebang `#!/usr/bin/env python3` et sont exécutables, donc `./scripts/sh-metrics.py report`
fonctionne directement sous Linux et macOS. La compétence résout
`PY="$(command -v python3 || command -v python)"` une fois par exécution, ce qui couvre les trois
plateformes, y compris Git Bash sous Windows.
**Strictement local.** Aucun des deux scripts ne contient de code réseau ni de point de rapport.
Tout ce qui ressemble à un jeton est masqué avant d'être écrit, car les fichiers locaux finissent collés
dans des tickets.
### L'exécuter sans surveillance
Facultatif, et c'est une décision distincte de l'utilisation de la compétence. Exécutez-la à la main sur vos propres PRs
pendant un moment d'abord, afin de savoir ce qu'elle dit de votre base de code avant qu'elle ne le dise
devant votre équipe.
Quand vous êtes prêt, « Enforcing the check on a repository » dans
[`references/pr-review-mapping.md`](https://github.com/dmdhrumilmistry/security-harness/blob/main/plugins/security-harness/references/pr-review-mapping.md)
contient un workflow à copier-coller pour **votre** dépôt, ainsi que le garde-fou qui empêche une tâche morte
de laisser une vérification requise bloquée sur `pending`.
Le seuil reste à la valeur par défaut `medium`. Les constats préexistants ne bloquent jamais une fusion,
donc une base de code non analysée ne produit pas un mur de rouge dès le premier jour - seul ce qu'une PR
introduit ou aggrave réellement peut la faire échouer.
## Comment ça fonctionne
1. **Configuration** - sonder les outils disponibles, définir la portée, créer le répertoire d'exécution.
2. **Reconnaissance** (`sh-recon`) - construire le graphe Graft ; détecter la pile/les versions ; SBOM + CVE ; énumérer les points
d'entrée, les frontières de confiance et les sinks dangereux.
3. **Chasse** (`sh-hunter` ×N, en parallèle) - un chasseur par classe pertinente charge sa base de connaissances `sh-kb-*`,
trace l'entrée de l'attaquant de la source au sink, et enregistre les candidats. Un **registre des tentatives** partagé empêche
les agents de répéter les sondes des autres.
4. **Chaînage** (`sh-chainer`) - composer les constats en chemins d'attaque de gravité supérieure.
5. **Vérification** (`sh-verifier`) - réfuter d'abord, puis confirmer l'exploitabilité à partir des preuves, construire des PoC, attribuer
un score CVSS, et éliminer les faux positifs.
6. **Rapport** (`sh-reporter`) - produire les livrables.
Les sous-agents ne partagent rien d'autre que des fichiers ; le contrat est dans `plugins/security-harness/references/state-files.md`.
## Extension
Ajoutez une nouvelle classe de vulnérabilité en créant `skills/sh-kb-<class>/SKILL.md` en suivant le modèle partagé
(Quand chasser · Sources & sinks · Recette de détection · Payloads/PoC · Filtres de faux positifs · CWE/OWASP ·
Indices de chaînage · Atténuation), puis ajoutez son slug à l'énumération `class` dans `references/finding-schema.json`
et à la table de routage dans `skills/sh-router/SKILL.md`.
## Mises à jour automatisées de la base de connaissances
Une GitHub Action planifiée (`.github/workflows/update-knowledge-base.yml`) maintient les bases de connaissances
`sh-kb-*` à jour. **Tous les deux jours** (et sur `workflow_dispatch` manuel), elle exécute un agent pour distiller de nouvelles
recherches de sécurité publiques réputées - OWASP, PortSwigger Research, CWE/CAPEC, NIST, MDN, dépôts GitHub
sélectionnés, et divulgations publiques HackerOne - en petites améliorations bien sourcées. Un **second agent réviseur,
adversarial** analyse ensuite le diff résultant à la recherche de contenu malveillant/injecté, et la PR est
**auto-fusionnée uniquement si ce réviseur approuve**.
### Deux workflows, trois jobs
La création de la PR est délibérément séparée de la révision et de la fusion, afin que ce qui écrit
le diff ne soit jamais ce qui décide de le livrer.
**Étape 1 - [`update-knowledge-base.yml`](https://github.com/dmdhrumilmistry/security-harness/blob/main/.github/workflows/update-knowledge-base.yml)**
(planifiée ou manuelle). Un job, `create-pr` :
1. **Générer** - l'agent modifie la KB à partir de sources autorisées. Pas de commit, pas de push.
2. **Ouvrir la PR** - une étape déterministe ouvre (ou met à jour) une PR sur la branche `automated/kb-update`,
étiquetée `awaiting-review`.
3. **Passer la main** - en cas de création réussie de la PR, elle déclenche l'étape 2 avec le numéro de PR.
**Étape 2 - [`kb-review-and-merge.yml`](https://github.com/dmdhrumilmistry/security-harness/blob/main/.github/workflows/kb-review-and-merge.yml)**
(déclenchée par l'étape 1, ou exécutée à la main contre n'importe quelle PR automatisée). Deux jobs :
- **`review`** - une exécution d'agent *séparée* inspecte le diff de manière **adversariale** à la recherche
d'artefacts d'injection de prompt, de modifications hors périmètre, de secrets/exfiltration, de PII, d'exploits
weaponisés, de sources hors liste blanche, ou de violations du style maison. Il n'a **ni web ni
shell**, et **échoue en fermant** : tout ce qui est suspect, toute incertitude, ou un fichier de verdict manquant → REJET. Le verdict est publié comme commentaire de PR et pilote l'étiquette.
- **`merge`** - s'exécute **uniquement** sur `APPROVE`, et fusionne la PR. Un `REJECT` l'ignore et
le job `blocked` rapporte pourquoi.
> **Pourquoi un dispatch plutôt qu'un déclencheur `pull_request` :** une PR ouverte par `GITHUB_TOKEN`
> ne déclenche pas les workflows `pull_request`. `workflow_dispatch` est l'un des deux événements
> exemptés de ce garde-fou de récursion, donc l'étape 1 peut passer la main de manière fiable.
**L'auto-fusion signifie qu'un agent approbateur atterrit du code dans `main`.** Les contrôles sur cela :
- Le job de fusion refuse toute PR qui est fermée, provenant d'un fork, ou dont la branche de tête est
en dehors de `automated/*` (`ALLOWED_HEAD_PREFIX` dans le workflow).
- Il privilégie l'auto-fusion de GitHub lui-même, donc **la protection de branche s'applique toujours**. Avec une règle
sur `main` exigeant une révision approbatrice, la PR fait la queue et attend un humain au lieu de
fusionner. Il se rabat sur une fusion immédiate uniquement sur les dépôts où l'auto-fusion est désactivée.
- Définissez l'entrée `auto_merge` sur `false` lors d'une exécution manuelle pour réviser sans fusionner.
- Le prompt du réviseur indique à l'agent que son verdict est contraignant, et non consultatif.
> Nécessite le paramètre de dépôt **« Allow GitHub Actions to create and approve pull requests »** (Settings →
> Actions → General → Workflow permissions) pour que le workflow puisse ouvrir la PR. Si vous voulez un humain dans la
> boucle malgré l'auto-fusion, protégez `main` avec une règle de protection de branche exigeant une pull request et au
> moins une révision approbatrice - le chemin d'auto-fusion la respecte.
### Agents enfichables
Les deux étapes passent par [`.github/actions/ai-agent`](https://github.com/dmdhrumilmistry/security-harness/blob/main/.github/actions/ai-agent/action.yml),
une action composite qui dispatche vers l'agent que vous configurez. Claude Code, OpenAI
Codex, Gemini CLI, et une porte de sortie pour tout le reste :
| `agent` | Exécute | Identifiant |
|---|---|---|
| `claude` (par défaut) | `anthropics/claude-code-action@v1` | `CLAUDE_CODE_OAUTH_TOKEN` ou `ANTHROPIC_API_KEY` |
| `codex` | `codex exec --full-auto` | `OPENAI_API_KEY` |
| `gemini` | `gemini --yolo --prompt` | `GEMINI_API_KEY` |
| `custom` | votre `KB_AGENT_INSTALL` / `KB_AGENT_COMMAND` | ce dont il a besoin |
Choisissez par exécution à partir des entrées `workflow_dispatch`, ou définissez des variables de dépôt pour changer la
valeur par défaut : `KB_AGENT` et `KB_MODEL` pour le générateur, `KB_REVIEW_AGENT` et
`KB_REVIEW_MODEL` pour le réviseur. Exécuter le générateur et le réviseur sur **des agents
différents** est une étape de durcissement significative : une injection adaptée à un modèle a moins de chances
d'atterrir sur un second, indépendant.
Pour `agent: custom`, définissez `KB_AGENT_COMMAND` sur une commande shell. Le prompt est écrit dans
le fichier nommé par `$AGENT_PROMPT_FILE`, et `$AGENT_MODEL` porte l'entrée du modèle.
Défenses contre l'injection de prompt, puisque le générateur lit le web ouvert :
- **Liste blanche de domaines.** `WebFetch` est restreint aux domaines de confiance dans
`.github/kb-update/trusted-sources.md` (reflétés dans les `--allowedTools` du workflow). `WebSearch` peut
découvrir des URLs, mais seuls les domaines en liste blanche peuvent réellement être récupérés.
- **Le contenu est une donnée, pas une commande.** Le prompt de tâche (`.github/kb-update/prompt.md`) demande à Claude de
traiter chaque octet récupéré comme du matériel de référence non fiable et d'ignorer toute instruction intégrée dans une
page - les corps de rapport HackerOne (générés par les utilisateurs) sont signalés comme le niveau de risque le plus élevé.
- **Pas de shell, pas de push sur le générateur ; le réviseur est la porte.** Le générateur ne peut que modifier des fichiers.
Le réviseur indépendant (`.github/kb-update/review-prompt.md`) est ce qui se tient entre le contenu récupéré
et `main` - rien ne fusionne sans son approbation explicite.
- **Des agents différents pour le générateur et le réviseur.** Facultatif, et la version la plus forte de la porte : définissez
`KB_AGENT` et `KB_REVIEW_AGENT` sur deux moteurs différents.
**Configuration :**
- Ajoutez l'identifiant de l'agent que vous utilisez (Settings → Secrets and variables → Actions) :
**`CLAUDE_CODE_OAUTH_TOKEN`** (par défaut), `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, ou `GEMINI_API_KEY`.
Le jeton OAuth s'authentifie contre **les limites d'usage de votre abonnement Claude** plutôt qu'une clé API
facturée à l'usage - générez-le localement avec `claude setup-token` (nécessite un abonnement Claude Pro/Max actif)
et collez le résultat.
- Activez **« Allow GitHub Actions to create and approve pull requests »** (Settings → Actions → General →
Workflow permissions) pour que le workflow puisse ouvrir sa PR. Recommandé : ajoutez une règle de protection de branche sur `main`
exigeant une PR et une révision approbatrice, afin qu'aucune modification automatisée ne puisse atterrir sans un humain, même avec
l'auto-fusion activée.
- Pour changer les sources autorisées, modifiez la liste blanche dans `trusted-sources.md` **et** les entrées
`WebFetch(domain:...)` correspondantes dans le workflow - gardez les deux synchronisées.
Chaque exécution enregistre ce qu'elle a fait dans `.github/kb-update/last-run-summary.md`.
## Feuille de route
- ~~Câblage du miroir Codex / Cursor.~~
✅ Livré : `AGENTS.md`, une extension Gemini CLI, et `scripts/sync-agent-skills.py`
pour `.agents/skills` et opencode. Voir [`docs/DISTRIBUTION.md`](https://github.com/dmdhrumilmistry/security-harness/blob/main/docs/DISTRIBUTION.md).
- ~~Augmentation optionnelle par récupération en direct des bases de connaissances (PortSwigger/OWASP/CWE) par-dessus les références sélectionnées.~~
✅ Livré sous la forme du programme de mise à jour planifié de la base de connaissances ci-dessus.
- Pont DAST optionnel pour la confirmation à l'exécution des constats `needs-runtime`.
## Licence
MIT