Un runner GitHub Actions peut, par défaut, contacter n'importe quelle adresse sur Internet. Si une dépendance ou une action tierce est compromise, elle exfiltre vos secrets sans rencontrer le moindre obstacle. Harden-Runner est un agent de sécurité qui fonctionne comme un EDR pour vos runners : il surveille le trafic réseau, l'intégrité des fichiers et les processus, puis vous laisse bloquer ce qui n'est pas explicitement autorisé. Ce guide vous montre comment l'auditer, restreindre son egress à une allowlist, désactiver sudo et repérer une compromission. Prérequis : un dépôt avec des workflows et la maîtrise de l'épinglage des actions par SHA. Exemples testés avec Harden-Runner v2.20.0.
Qu'est-ce que Harden-Runner ?
Section intitulée « Qu'est-ce que Harden-Runner ? »Harden-Runner est une action open source éditée par StepSecurity qui installe un agent de sécurité sur le runner, au tout début du job. Là où les scanners comme zizmor ou poutine analysent vos fichiers de workflow avant exécution, Harden-Runner agit pendant le build. Il observe en temps réel trois choses :
- le trafic réseau sortant (egress), chaque connexion étant rattachée au step qui l'émet ;
- l'intégrité des fichiers modifiés durant le job ;
- les processus lancés sur le runner.
C'est cette surveillance à l'exécution qui a permis de détecter des attaques supply chain réelles, comme la compromission de l'action tj-actions/changed-files en 2025, où un runner exfiltrait des secrets vers une adresse inattendue.
Le problème : un runner qui peut tout exfiltrer
Section intitulée « Le problème : un runner qui peut tout exfiltrer »Prenons un workflow d'intégration continue banal. Il récupère le code, installe des dépendances, lance des tests. Rien de suspect en apparence, mais rien ne limite le réseau : si l'une des dépendances installées contient une charge malveillante, elle peut expédier GITHUB_TOKEN ou vos secrets vers le serveur de l'attaquant, et le build réussira comme si de rien n'était.
Premier réflexe : le mode audit
Section intitulée « Premier réflexe : le mode audit »On ne bloque jamais à l'aveugle. La bonne démarche commence par le mode audit, qui observe sans rien couper et dresse la liste des endpoints réellement contactés par votre workflow. Harden-Runner doit être le tout premier step du job, avant le checkout, pour intercepter l'ensemble du trafic. Épinglez-le par SHA, comme toute action tierce :
name: CI durci
on: push: branches: [main]
permissions: {}
jobs: build: name: Build et test runs-on: ubuntu-24.04 timeout-minutes: 10 permissions: contents: read steps: - name: Durcir le runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit
- name: Récupérer le code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false
- name: Construire run: make buildÀ l'issue du run, Harden-Runner publie une synthèse des connexions dans les logs du job et sur le tableau de bord StepSecurity. Vous y voyez chaque destination jointe, associée au step qui l'a émise : le point de départ pour établir votre allowlist.
Lire les insights
Section intitulée « Lire les insights »Le résultat de l'audit est consultable de deux façons. Dans l'onglet du job, Harden-Runner ajoute un récapitulatif listant les domaines contactés. Sur le tableau de bord app.stepsecurity.io, une vue plus riche corrèle connexions, fichiers et processus, et vous propose directement les recommandations de durcissement, par exemple désactiver sudo si le job ne s'en sert pas.
L'objectif de cette lecture est simple : distinguer les endpoints légitimes (le registre de paquets, l'API GitHub, votre miroir interne) des connexions que vous ne vous expliquez pas. Les premiers formeront l'allowlist, les secondes méritent une enquête.
Bloquer l'egress avec une allowlist
Section intitulée « Bloquer l'egress avec une allowlist »Une fois la liste des destinations légitimes établie, passez egress-policy à block et déclarez-les dans allowed-endpoints, au format hôte:port, une par ligne. Toute connexion vers une destination absente de la liste est alors coupée, aux couches DNS et réseau.
- name: Durcir le runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: block allowed-endpoints: > github.com:443 api.github.com:443 objects.githubusercontent.com:443Désormais, la charge malveillante du scénario précédent se heurte à un mur : sa tentative de connexion vers le serveur de l'attaquant est bloquée, et l'événement apparaît en rouge dans les insights. Le filtrage egress transforme une exfiltration silencieuse en alerte visible.
Durcir davantage le runner
Section intitulée « Durcir davantage le runner »Le filtrage egress se complète de deux réglages utiles. Les runners GitHub-hosted accordent un sudo sans mot de passe : un outil de build compromis peut donc installer ce qu'il veut. Si votre job n'en a pas besoin, coupez cet accès. L'input historique disable-sudo est en cours de dépréciation au profit de disable-sudo-and-containers, qui retire aussi l'accès aux conteneurs :
- name: Durcir le runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: block disable-sudo-and-containers: true allowed-endpoints: > github.com:443 api.github.com:443L'input disable-telemetry empêche l'agent d'envoyer ses données à l'API StepSecurity, utile si votre politique interdit toute télémétrie sortante. Pour les organisations, une policy centralisée (inputs policy, api-key, use-policy-store) permet de définir l'allowlist une seule fois et de l'appliquer à tous les dépôts, plutôt que de la répéter dans chaque workflow.
Pièges et limites
Section intitulée « Pièges et limites »Harden-Runner est un excellent garde-fou, à condition de connaître ses bornes.
| Piège | Réalité | Bon réflexe |
|---|---|---|
Placer l'action après checkout | Le trafic antérieur échappe à la surveillance | En faire le premier step du job |
L'épingler par tag @v2 | Une action tierce mobile peut être détournée | Épingler par SHA (règle GHA-01) |
| Croire le blocage infaillible | Un contournement egress via DNS-over-HTTPS a existé sur l'offre gratuite | Tenir l'agent à jour, combiner à d'autres contrôles |
Compter sur disable-sudo seul | La CVE-2025-32955 permettait de le contourner | Version ≥ 2.12.0 et disable-sudo-and-containers |
| L'attendre partout | L'agent cible les runners Ubuntu | Prévoir une autre approche sur macOS/Windows |
Retenez surtout que Harden-Runner s'inscrit dans une défense en profondeur. Il ne remplace ni l'épinglage par SHA, ni les permissions minimales, ni l'analyse statique des workflows : il ajoute la couche d'exécution qui manquait, celle qui voit ce qui se passe pendant le build.
Community ou Enterprise ?
Section intitulée « Community ou Enterprise ? »Harden-Runner se décline en deux offres. La version Community, gratuite et suffisante pour l'essentiel, couvre exactement ce que montre ce guide : audit et blocage de l'egress, allowlist d'endpoints, désactivation de sudo, et le récapitulatif des connexions dans le job. C'est le socle à déployer sur tous vos dépôts.
L'offre Enterprise ajoute une gestion centralisée (le policy store, pour définir une politique unique appliquée à toute l'organisation), une surveillance plus fine des processus, la corrélation historique des exécutions et des alertes sur comportements anormaux. Elle vise les équipes qui doivent prouver et piloter la conformité de nombreux pipelines. Commencez par la version Community : elle bloque déjà la classe d'attaques la plus courante.
À retenir
Section intitulée « À retenir »- Harden-Runner surveille un runner GitHub Actions à l'exécution : trafic egress, intégrité des fichiers, processus.
- Commencez toujours en
egress-policy: auditpour découvrir les endpoints réellement utilisés. - Passez ensuite en
blockavecallowed-endpoints(hôte:port) pour couper toute exfiltration. - Faites-en le premier step du job et épinglez-le par SHA, sinon la protection est incomplète.
- Coupez sudo avec
disable-sudo-and-containers(qui remplacedisable-sudo) quand le job n'en a pas besoin. - C'est une couche de défense en profondeur, pas un substitut à l'épinglage, aux permissions minimales et à l'analyse statique.