# Tester les SSRF des outils d'agent qui injectent des identifiants

Un outil d'agent qui injecte des identifiants transforme les requêtes HTTP sortantes ordinaires en décision de frontière. Si l'outil accepte une destination fournie par un agent, valide un nom d'hôte d'apparence rassurante, puis laisse son client HTTP aller là où le DNS et les redirections le conduisent, il a remis son identifiant à un service choisi par l'attaquant.

La solution n'est pas de coller une liste de refus plus longue dans un validateur d'URL. Il faut une matrice de destinations qui couvre tout le cycle de la requête : analyse, résolution DNS, choix de l'adresse, connexion, gestion des redirections, puis seulement injection des identifiants. Le test doit observer le pair qui a reçu la requête, car c'est là que le secret est arrivé.

## L'injection des identifiants doit suivre l'approbation de la destination

L'outil doit décider s'il peut contacter une destination avant d'y ajouter la moindre donnée d'authentification. Les jetons bearer, les identifiants Basic, les en-têtes personnalisés, les signatures de requête, les certificats client et les identités SSH doivent donc tous intervenir après le contrôle de destination.

Les équipes placent souvent ce contrôle au mauvais endroit. Elles valident la chaîne URL d'origine, construisent une requête avec un en-tête Authorization, puis appellent un helper HTTP pratique avec le suivi des redirections activé. Le helper résout alors les noms, choisit IPv6 ou IPv4, suit un en-tête Location et peut réutiliser des en-têtes ou l'état d'une connexion d'une manière que le code de validation n'a jamais vue.

Cette conception a un avantage : elle est facile à écrire. Elle laisse aussi la décision dangereuse à un composant qui ignore que la requête transporte un identifiant.

Séparez les deux décisions :

- Cette URL est-elle syntaxiquement acceptable pour l'outil ?
- Cette destination réseau concrète est-elle approuvée pour une connexion authentifiée ?

La première décision analyse le schéma, l'hôte, le port, le chemin, les informations utilisateur et l'encodage en pourcentage. La seconde classe les adresses résolues et contrôle la connexion réelle. Une liste blanche d'hôtes peut contribuer aux deux décisions, mais elle ne remplace pas la seconde.

La RFC 3986 rend le problème d'analyse très clair. La composante d'autorité suit la forme `[userinfo@]host[:port]` ; une chaîne qui contient visuellement un nom d'hôte de confiance avant `@` peut tout de même désigner l'adresse IP située après celui-ci. La RFC 3986 utilise même cette construction dans son analyse des chaînes d'autorité URI trompeuses. Ne découpez pas vous-même les URL et ne recherchez pas un nom de confiance dans la chaîne brute. Utilisez un analyseur conforme aux standards, refusez les informations utilisateur pour les destinations si l'outil n'en a pas un besoin légitime, puis lisez le champ d'hôte analysé.

L'invariant de sécurité est suffisamment simple pour être testé :

> L'outil ne doit envoyer aucun octet authentifié avant d'avoir approuvé le pair connecté et l'autorité de la requête concernée.

Un « octet authentifié » inclut la ligne de requête ou l'en-tête Host uniquement lorsque ces valeurs révèlent elles-mêmes un secret. Dans la plupart des cas HTTP, la limite essentielle est l'en-tête qui porte l'identifiant ou la charge utile signée. Soyez plus strict lorsque le chemin, la chaîne de requête ou le corps contient une URL à capacité, un identifiant de locataire ou une autre valeur sensible.

## Définissez le point de décision avant d'écrire les cas de test

Impossible de tester un contrôle SSRF tant que vous ne pouvez pas nommer précisément le point où il autorise ou refuse une requête. « Avant la requête » est trop vague. Une requête comporte plusieurs moments où la cible peut changer.

Utilisez cette séquence comme modèle pour un outil HTTP qui injecte des identifiants :

1. Analysez l'URL absolue fournie et refusez les schémas non pris en charge, les autorités malformées, les informations utilisateur et les ports qui sortent du contrat de l'outil.
2. Résolvez le nom d'hôte avec le résolveur réellement utilisé par le processus. Récupérez les réponses A et AAAA, et pas uniquement celle que votre machine de développement a choisi de préférence.
3. Classez chaque adresse candidate. Refusez la requête si l'ensemble contient une adresse qui ne fait pas partie des classes de destinations approuvées, sauf si le connecteur peut se fixer sur une adresse autorisée.
4. Ouvrez une connexion vers une adresse approuvée, puis vérifiez l'adresse du pair distant avant d'écrire l'identifiant.
5. Construisez la requête authentifiée seulement après cette vérification. Définissez délibérément l'en-tête Host et le nom de serveur TLS attendus.
6. Traitez une redirection comme une nouvelle requête qui recommence à l'analyse, et non comme une continuation qui hérite de la confiance.

C'est plus exigeant que de vérifier `hostname != "localhost"`. C'est nécessaire. La RFC 8305 décrit des clients qui émettent des requêtes AAAA et A à peu près simultanément et essaient les adresses en tenant compte d'une préférence IPv6. Une suite qui ne résout que les enregistrements A peut certifier un code qui échoue dès qu'un enregistrement AAAA accessible apparaît.

Le point de décision détermine aussi ce que votre banc de test doit enregistrer. Pour chaque tentative, capturez :

- l'URL reçue par l'outil
- les réponses DNS renvoyées à l'outil
- l'adresse choisie pour la connexion
- l'adresse observée par le serveur destinataire
- tous les en-têtes de la requête, en masquant les identifiants de test dans les rapports

N'utilisez pas un test qui vérifie uniquement un code d'état ou une exception. Un 403 renvoyé par votre serveur de capture prouve qu'il a reçu la requête. Un délai d'attente ne prouve souvent rien. L'assertion recherchée est : « Le service d'écoute bloqué n'a observé aucune requête contenant un identifiant. »

## Construisez la matrice autour des destinations, pas des noms d'hôte

Une matrice de destinations est l'artefact durable de ce travail. Chaque ligne indique une forme d'entrée, la réponse du résolveur, le comportement éventuel d'une redirection et le résultat attendu. Elle évite la dérive habituelle : un développeur teste `127.0.0.1`, un autre `10.0.0.1`, et personne ne teste les formes étranges acceptées par le runtime.

Commencez par une petite matrice avec une vraie référence de vérité. L'exemple ci-dessous suppose que `public.test` pointe vers un service d'écoute de test classé comme autorisé, tandis que toute autre classe d'adresse doit être refusée avant l'injection des identifiants.

| Cas | URL soumise | Comportement DNS ou redirection | Résultat attendu |
| --- | --- | --- | --- |
| IPv4 publique | `https://public.test/echo` | Enregistrement A vers le service public de test | Autoriser et envoyer l'identifiant de test |
| Boucle locale IPv4 | `http://127.0.0.1:18080/` | Adresse littérale | Refuser avant la connexion |
| Variante de boucle locale IPv4 | `http://127.1:18080/` | Forme abrégée dépendante de l'analyseur | Refuser ou classer comme boucle locale, jamais autoriser |
| Privée RFC 1918 | `http://10.20.30.40/` | Adresse littérale | Refuser avant la connexion |
| Privée RFC 1918 | `http://172.20.30.40/` | Adresse littérale | Refuser avant la connexion |
| Privée RFC 1918 | `http://192.168.20.40/` | Adresse littérale | Refuser avant la connexion |
| Boucle locale IPv6 | `http://[::1]:18080/` | Adresse littérale | Refuser avant la connexion |
| Link-local IPv6 | `http://[fe80::1]/` | Adresse littérale | Refuser avant la connexion |
| IPv6 mappée sur IPv4 | `http://[::ffff:127.0.0.1]/` | Adresse littérale | Refuser avant la connexion |
| Réponse DNS mixte | `https://mixed.test/` | A autorisée, AAAA bloquée | Refuser ou fixer la connexion sur l'adresse autorisée |
| Nom avec rebinding | `https://rebind.test/` | Première réponse autorisée, suivante bloquée | Refuser la requête authentifiée vers le pair bloqué |
| Redirection vers la boucle locale | `https://public.test/to-local` | 302 vers `http://127.0.0.1:18080/` | Refuser la seconde requête |
| Redirection vers un DNS privé | `https://public.test/to-private` | 302 vers `https://internal.test/` | Résoudre et refuser la seconde requête |
| Tromperie par informations utilisateur | `http://public.test@127.0.0.1/` | Hôte littéral situé après `@` | Refuser avant la connexion |

La RFC 1918 ne définit que trois plages IPv4 privées : 10/8, 172.16/12 et 192.168/16. Testez les limites, notamment `172.15.255.255`, `172.16.0.0`, `172.31.255.255` et `172.32.0.0`. Un contrôle de préfixe approximatif bloque souvent tout 172/8, ce qui casse des points de terminaison publics légitimes, ou uniquement 172.16/16, ce qui laisse passer la plus grande partie de la plage privée allouée.

Ne prenez pas ce tableau pour une politique de production universelle. Certains outils internes doivent pouvoir contacter un service privé précis. Si c'est votre besoin produit, donnez à ce service une règle explicite avec un nom d'hôte, un port et un contrôle d'identité stricts. Ne faites pas de « les adresses privées sont acceptables dans notre bureau » la règle par défaut pour toute destination choisie par un agent.

## Les tests d'analyse d'URL détectent les erreurs avant le DNS

L'analyseur doit identifier l'hôte que le connecteur utilisera. Cela semble évident, jusqu'à ce qu'un test révèle qu'un composant normalise l'entrée différemment d'un autre.

Placez les cas suivants dans une suite réservée à l'analyse. Ils doivent s'exécuter sans DNS ni socket réseau :

```text
http://public.test@127.0.0.1/admin
http://127.0.0.1.nip.example/
http://[::1]/
http://[::ffff:7f00:1]/
http://0177.0.0.1/
http://2130706433/
http://127.0.0.1%2f.example/
http://public.test:80@127.0.0.1/
http://public.test./
```

Le résultat attendu n'est pas toujours « cette chaîne exacte doit être analysée comme une adresse de boucle locale ». Les bibliothèques URI et URL diffèrent dans leur traitement des anciennes formes IPv4 numériques, des identifiants de zone et des encodages en pourcentage invalides. Votre test doit exprimer la propriété de sécurité : si le runtime accepte l'entrée et la connecte à une adresse bloquée, l'outil doit la refuser. Si le runtime la rejette, c'est acceptable.

Cette distinction est importante, car de nombreuses équipes écrivent d'abord un filtre d'hôte personnalisé, puis transmettent l'URL inchangée à une autre bibliothèque. Le filtre peut considérer `2130706433` comme un nom enregistré inconnu, alors que le connecteur l'interprète comme 127.0.0.1. Vous venez de tester deux analyseurs et de faire confiance à la réponse la plus sûre.

Utilisez la même représentation analysée pour la validation et la connexion. Lorsque ce n'est pas possible, demandez au connecteur final de signaler le pair numérique qu'il a choisi, puis effectuez un dernier contrôle de classe d'adresse avant que les identifiants ne quittent le processus.

Testez également la normalisation des noms d'hôte. Un point final dans `public.test.` désigne le même nom DNS que `public.test` dans l'usage DNS courant, mais les listes blanches simplistes comparent souvent les chaînes brutes. Les noms d'hôte internationalisés ajoutent une autre source de désaccord. Convertissez une seule fois le nom dans la représentation canonique du runtime, puis comparez les noms DNS sur les limites de leurs étiquettes. Un contrôle de suffixe comme `endsWith("trusted.example")` accepte `untrusted.example` et `trusted.example.attacker.test` ; aucun des deux n'est un sous-domaine de confiance.

## Les tests de rebinding DNS doivent imposer la seconde résolution

Le rebinding DNS est une faille de synchronisation. La première résolution renvoie une adresse acceptable. Une résolution ultérieure du même nom renvoie la boucle locale, une adresse privée ou une autre cible bloquée. Si la validation et la connexion n'utilisent pas le même résultat de résolution, un attaquant peut passer le premier contrôle et détourner le second.

Un bon dispositif de test nécessite un petit serveur DNS faisant autorité que vous contrôlez et deux services HTTP d'écoute. Le premier est votre service autorisé. Le second est un service bloqué qui enregistre la réception éventuelle de l'en-tête Authorization de test. Donnez au serveur DNS la séquence de réponses suivante pour `rebind.test` :

```text
query 1: rebind.test. A     198.51.100.20
query 2: rebind.test. A     127.0.0.1
query 1: rebind.test. AAAA  2001:db8::20
query 2: rebind.test. AAAA  ::1
```

Utilisez des adresses réservées au banc de test et faites pointer le service autorisé dans le réseau de test selon vos besoins. Les adresses d'apparence publique utilisées dans cet exemple sont des identifiants du dispositif de test, et non des points de terminaison que le test devrait contacter sur Internet.

Exécutez maintenant deux variantes. Dans la première, faites effectuer à l'outil sa propre résolution de validation, puis appelez une bibliothèque HTTP qui résout les noms séparément. Le service bloqué doit recevoir l'identifiant si l'implémentation présente la faille recherchée. Dans la seconde, configurez le chemin de connexion pour utiliser l'adresse résolue approuvée, conservez le nom d'hôte d'origine uniquement pour la vérification du nom Host et du nom TLS, puis vérifiez que le service bloqué n'observe rien.

La mise en cache peut masquer le problème. Le cache d'un résolveur, un pool de connexions ou le cache du système d'exploitation peut transformer votre seconde réponse en événement sans effet. Le banc de test doit permettre de contrôler le cache, fermer les connexions inactives entre les exécutions, utiliser un nom d'hôte différent à chaque exécution si nécessaire et enregistrer chaque requête DNS. Si un test de rebinding réussit sans confirmer deux résolutions distinctes, il n'a pas testé le rebinding.

Ne résolvez pas le problème en faisant confiance au TTL DNS. Le TTL est une indication de mise en cache, pas une garantie qu'un nom restera sûr entre la validation et la connexion. Le code doit transmettre l'adresse approuvée à la connexion ou vérifier le pair après l'ouverture du socket.

## Les redirections sont des décisions de destination distinctes

Une redirection modifie la destination. Elle peut changer le schéma, l'hôte, le port, le chemin ou les quatre à la fois. La traiter comme une continuation de confiance est le moyen de transformer une URL publique apparemment sûre en requête vers `127.0.0.1`, un service de métadonnées d'instance, un routeur ou un plan de contrôle interne.

Désactivez le suivi automatique des redirections dans le transport utilisé par la requête qui porte les identifiants. Lisez la réponse de redirection, imposez une limite raisonnable, analysez la valeur Location par rapport à l'URL actuelle selon les règles de résolution de la bibliothèque et recommencez toute la décision de destination.

Votre dispositif de redirection doit au minimum couvrir les comportements suivants :

- Une URL publique renvoie un 302 vers un littéral IPv4 de boucle locale.
- Une URL publique renvoie un 307 vers un nom d'hôte qui se résout vers une adresse IPv4 privée.
- Une URL publique renvoie une valeur Location relative comme `/next`, qui doit rester sur l'autorité déjà approuvée après résolution normale.
- Une URL publique renvoie une valeur Location relative au schéma comme `//other.test/path`, ce qui change l'autorité et exige une validation complète.
- Une URL publique renvoie une chaîne de redirections dont le premier saut est autorisé et un saut ultérieur bloqué.

Les codes d'état comptent. Un 301, 302 ou 303 peut inciter les clients à transformer une méthode autre que GET en GET. Un 307 ou 308 est censé conserver la méthode et le corps. Ne vous fiez pas au comportement par défaut d'une bibliothèque lorsqu'il s'agit d'un POST signé ou d'une écriture authentifiée par bearer. Enregistrez la méthode, le hachage du corps, l'en-tête Host et l'en-tête Authorization dans chaque service de redirection.

Supprimer Authorization lorsque l'autorité change est une bonne défense, mais cela ne rend pas la validation de destination facultative. Une requête sans en-tête Authorization peut toujours contenir une URL signée dans le chemin, un certificat client, des cookies ou un corps sensible. Une redirection vers le même hôte peut aussi mener d'un chemin ordinaire à un service local si le DNS change entre deux étapes.

C'est un cas où le test doit être volontairement simple. Faites renvoyer 200 au service de redirection bloqué. Si votre assertion attend seulement une erreur côté client, un client qui suit les redirections peut effectuer la requête SSRF avec succès et votre test la considérera comme réussi pour la mauvaise raison. Vérifiez le nombre de requêtes capturées par le service d'écoute et la présence d'identifiants dans celles-ci.

## IPv6 est une surface SSRF à part entière

L'oubli d'IPv6 est généralement accidentel. Un développeur teste `127.0.0.1`, bloque les plages RFC 1918 et livre un code qui considère `[::1]` comme un nom d'hôte exotique. Les clients modernes peuvent interroger les enregistrements AAAA en parallèle des enregistrements A, et une route IPv6 peut être choisie même lorsque les tests IPv4 sont propres.

La RFC 4291 définit `::1/128` comme l'adresse de boucle locale IPv6 et `::/128` comme l'adresse non spécifiée. Elle définit également les adresses unicast link-local dans `fe80::/10`. Ce sont des classes d'adresses qui ne doivent jamais devenir par accident une destination authentifiée choisie par un agent.

Testez explicitement les catégories suivantes :

| Classe d'adresse | Exemple | Résultat attendu par défaut |
| --- | --- | --- |
| Non spécifiée | `[::]` | Refuser |
| Boucle locale | `[::1]` | Refuser |
| Link-local | `[fe80::1]` | Refuser |
| Locale unique | `[fc00::1]`, `[fd12:3456::1]` | Refuser sauf approbation explicite |
| Multicast | `[ff02::1]` | Refuser |
| Boucle locale mappée sur IPv4 | `[::ffff:127.0.0.1]` | Refuser |
| Privée mappée sur IPv4 | `[::ffff:192.168.1.10]` | Refuser |

La classification doit s'effectuer sur l'adresse binaire, pas sur son écriture. Une même adresse peut apparaître sous forme IPv6 compressée ou développée. Une comparaison de chaînes avec `::1` ne détecte pas `0:0:0:0:0:0:0:1`. Analyser d'abord l'adresse avec un véritable type IP est une étape peu spectaculaire qui évite cette catégorie de défauts.

Les identifiants de portée méritent également une règle claire. Une entrée comme `[fe80::1%25en0]` contient une zone d'interface après encodage en pourcentage. La plupart des outils devraient refuser les destinations littérales avec portée fournies par un agent plutôt que d'essayer de décider quelle interface locale est sûre. Si le produit a un cas d'usage légitime sur le réseau local, faites du choix de l'interface une configuration explicite appartenant à l'utilisateur, jamais un détail d'URL fourni par l'agent.

Les réponses A et AAAA mixtes exigent une décision stricte. Si le résolveur renvoie une adresse IPv4 autorisée et une adresse IPv6 bloquée, le choix le plus sûr est le refus. Si la disponibilité impose d'utiliser la réponse autorisée, le connecteur doit fixer le socket sur cette adresse et ne doit pas transmettre ensuite le nom d'hôte à un résolveur. « Nous préférons IPv4 » n'est pas un contrôle. Les bibliothèques réseau, les systèmes d'exploitation et les courses de connexion peuvent faire un autre choix.

## Exécutez la matrice dans un banc de test fermé

Ne dirigez pas les tests SSRF vers les services localhost réels de votre ordinateur ni vers un point de terminaison de métadonnées cloud. Vous voulez des preuves, pas un après-midi stressant. Placez le résolveur et tous les services d'écoute dans un réseau de test isolé, utilisez des identifiants jetables et faites enregistrer par les services leur propre adresse et les en-têtes reçus.

Un banc simple comporte quatre acteurs :

1. Un exécuteur de test qui appelle l'outil avec une URL et une référence d'identifiant jetable.
2. Un serveur DNS contrôlable qui peut renvoyer des réponses A et AAAA dans un ordre programmé.
3. Un service HTTP autorisé qui enregistre les requêtes authentifiées réussies.
4. Un service HTTP bloqué qui enregistre toute connexion ou requête comme un échec de test.

Donnez au service bloqué un corps de réponse qui rend les fuites évidentes dans les journaux locaux, mais n'imprimez jamais un jeton complet. Il peut par exemple renvoyer l'adresse du pair, la méthode, l'en-tête Host et une valeur booléenne indiquant si `Authorization` était présent. L'exécuteur compare ces éléments à la ligne attendue de la matrice.

Le format des résultats doit être assez simple pour être inspecté dans CI :

```text
case=redirect_to_loopback
submitted=https://public.test/to-local
resolved=198.51.100.20
redirect=http://127.0.0.1:18080/
decision=deny
allowed_requests=0
blocked_connections=0
blocked_credentials=0
```

Un échec doit conserver les mêmes champs et ajouter le pair réel. Le rapport devient ainsi directement exploitable :

```text
case=rebind_ipv6
submitted=https://rebind.test/export
validation_answer=2001:db8::20
connected_peer=::1
blocked_credentials=1
result=FAIL
```

Ce rapport identifie immédiatement le défaut : le code a approuvé une réponse DNS et s'est connecté à une autre. Il indique aussi si l'identifiant a franchi la frontière, ce qui est le risque important.

Si votre outil prend en charge la configuration d'un proxy, ajoutez des lignes de proxy à la matrice. Un proxy HTTP modifie la destination de la connexion TCP, tandis que CONNECT peut tout de même amener le proxy à contacter une cible choisie par l'attaquant. Décidez si le proxy est lui-même un transport de confiance et si l'outil valide l'autorité finale. Un test qui vérifie seulement l'adresse du proxy peut certifier un relais ouvert vers des destinations internes.

## Séparez l'autorité et la destination dans l'implémentation

TLS rend ce problème facile à confondre. Pour se connecter en sécurité à un nom d'hôte, l'outil peut devoir ouvrir un socket vers une adresse numérique approuvée tout en présentant le nom d'hôte approuvé d'origine comme nom de serveur TLS et en-tête HTTP Host. Ce sont des champs différents, avec des rôles différents.

Le pair numérique répond à la question « Vers où va ce socket ? ». Le nom de serveur TLS répond à « Quelle identité de certificat ce serveur doit-il prouver ? ». L'en-tête Host répond à « Quelle autorité HTTP cette requête cible-t-elle ? ». Votre implémentation doit conserver explicitement ces trois valeurs au lieu de laisser une API HTTP pratique les déduire d'une chaîne URL modifiable.

Cette séparation met aussi en évidence une mauvaise recommandation encore répandue : résoudre une fois, puis remplacer le nom d'hôte de l'URL par l'adresse numérique. Cela peut éviter une seconde résolution DNS, mais peut casser la validation du certificat TLS, l'hébergement virtuel et les schémas de requêtes signées. Les développeurs désactivent alors souvent la vérification du certificat ou affaiblissent les contrôles d'hôte. C'est pire que le défaut initial.

Utilisez plutôt un transport capable de composer le numéro vers l'adresse approuvée tout en conservant une validation TLS stricte du nom d'hôte d'origine. Après l'établissement de la connexion, confirmez que le pair du socket est bien l'adresse approuvée. Si votre runtime ne propose pas ces contrôles, ne prétendez pas empêcher le rebinding DNS pour les requêtes authentifiées des agents. Inscrivez cette limite dans la frontière du produit et évitez d'injecter des identifiants dans les destinations choisies par les agents.

SSH suit le même modèle, même s'il n'utilise pas les redirections HTTP. Résolvez et classez l'hôte demandé, fixez la connexion sur l'adresse approuvée et vérifiez la clé d'hôte par rapport à l'identité attendue. Une demande de clé d'hôte ou une règle permissive de known-hosts ne constitue pas une politique de destination.

Sallyport conserve les identifiants dans son coffre chiffré et exécute lui-même les actions HTTP et SSH au lieu de remettre les secrets à l'agent. Cette frontière ne tient que si la couche d'action applique les contrôles de destination avant d'utiliser un identifiant stocké.

## Faites de la matrice un critère de livraison, pas un document de sécurité

Une matrice de destinations n'est utile que si elle s'exécute sur le même chemin de requête que celui livré. Un test unitaire de `isPrivateIp()` ne teste ni le résolveur du client HTTP, ni le code de redirection, ni le comportement du proxy, ni le pool de connexions. Gardez ces tests unitaires, mais rendez la suite du banc obligatoire lorsque vous mettez à jour la bibliothèque de transport, l'analyseur d'URL, la configuration du résolveur ou le code d'injection des identifiants.

Ajoutez des lignes lorsque vous corrigez un défaut. Ne réduisez pas un incident pénible à une formule générale comme « améliorer la validation SSRF ». Conservez l'entrée exacte, la séquence DNS, la réponse de redirection et l'absence attendue d'identifiants. Les futurs mainteneurs ont besoin de cette expérience sous une forme exécutable.

Examinez les échecs par catégorie. Les divergences d'analyse indiquent la présence de traitements URL en double. Si un service bloqué voit une connexion TCP mais aucune requête, vous avez peut-être validé trop tard, même si aucun jeton n'a fuité. Si le service bloqué voit un en-tête Authorization, l'invariant a échoué et la livraison doit être interrompue.

Le travail porte ses fruits parce qu'il change la question posée par l'équipe. Ne demandez plus si un nom d'hôte semblait externe. Demandez quel pair a reçu une requête authentifiée, comment il a été choisi et si votre test peut le prouver. Si la sortie du test ne permet pas de répondre, l'outil présente encore un angle mort SSRF.
