La wordlist connaissait déjà votre répertoire personnel
F5 Labs a relevé 807 attaques et 32 000 événements en un mois contre des serveurs de développement Vite exposés, au moyen d'une astuce de chaîne de requête qui passe tout droit devant la deny-list de Vite elle-même. Les scanners ne cherchent pas votre application. Ils demandent /home/ubuntu/.aws/credentials par chemin absolu, et /proc/self/environ, et terraform.tfstate. Dans un workspace Bromure Agentic Coding, ce port fait face à un switch privé, et le fichier que réclame la wordlist ne contient aucune clé.
Cet attaquant ne vous envoie ni paquet ni archive. C'est votre propre serveur de développement qui écoute, et un inconnu lui réclame des fichiers par leur nom. La machine qui répond décide de ce qu'il obtient.
Vous demandez à l'agent de lancer le frontend pour pouvoir y jeter un œil. Il
tape npm run dev, ouvre le port, charge la page, et vous retournez à la
relecture du diff. Quelque part dans cette boucle, dans un docker-compose.yml
ou dans un drapeau --host que vous aviez ajouté il y a des semaines pour rendre
l'aperçu accessible depuis votre téléphone, le serveur s'est lié à toutes les
interfaces plutôt qu'à la boucle locale. Douze minutes plus tard, quelque chose
qui se présente comme Googlebot demande à votre serveur de développement
/@fs/../.env?raw?? et reçoit un HTTP 200.
F5 Labs a publié les chiffres le 11 septembre. Sur un seul mois de données de capteurs, en août 2026, leurs honeypots ont enregistré 807 attaques regroupées par session et environ 32 000 événements bruts visant des serveurs de développement Vite exposés, contre une base de 1 732 événements sur les trois mois précédents. Soit dix-huit fois le trafic, d'un mois sur l'autre, pour un seul bogue. BleepingComputer l'a couvert le 14 septembre.
Une chaîne de requête qui contourne la deny-list
Vite sert des fichiers du système de fichiers de l'hôte par une route interne
appelée /@fs/, celle qui permet au serveur de développement de remettre à votre
éditeur un module situé hors de la racine du projet. Parce que cette route peut
atteindre n'importe quoi, Vite livre une deny-list, server.fs.deny, pour
bloquer les cibles évidentes : fichiers .env, certificats, sources privées.
CVE-2026-39364, publiée le 7 avril, permet à un attaquant de sauter cette deny-list en décorant la requête d'une chaîne de requête. F5 décrit le mécanisme :
Le serveur traite la requête, normalise le chemin, puis supprime ou interprète mal la chaîne de requête pendant la validation d'accès, si bien que le contrôle server.fs.deny n'est pas déclenché.
Le serveur n'applique pas le filtrage par deny-list et sert le fichier visé avec une réponse HTTP 200.
Le bogue affecte Vite 7.1.0 à 7.3.2, et les 8.x avant 8.0.5. F5 a intercepté ces
formes de requête dans la nature, chacune assez courte pour tenir sur une ligne :
GET /@fs/.env?raw??, GET /@fs/../.env?raw??,
GET /@fs/..%252f..%252f..%252f..%252froot/.env?raw?? et
GET /@fs/..%252f..%252f..%252f..%252fproc/self/environ?raw??. D'autres
variantes du même outillage utilisent ?import&raw, ?import&url&inline,
?inline&import et ?raw?import.
Ces astuces de paramètres portent leurs propres numéros de CVE :
CVE-2025-30208, CVE-2025-31125 et CVE-2024-45811, trois contournements plus
anciens de @fs toujours chargés dans les mêmes scanners. Celui qui pilote la
flotte de scan n'a pas réoutillé pour un nouveau bogue. Il a ajouté une ligne de
plus à un fichier qu'il possédait déjà.
La wordlist est une carte de la machine d'un développeur
Lisez ce que réclament les scanners, et voyez à quel point cela concerne peu votre application.
Ils demandent .env, .env.local, .env.production, .env.development et
.env.staging. Ils demandent terraform.tfstate, terraform.tfvars,
.terraform/terraform.tfstate, serverless.yml et
.serverless/serverless-state.json. Ils demandent .azure/credentials et
.azure/accessTokens.json. Ils demandent /etc/passwd, /proc/1/environ,
/proc/self/cwd/.env et /proc/self/environ. Ce dernier chemin contient le bloc
d'environnement du processus du serveur de développement lui-même, là où
atterrit une API_KEY exportée par votre shell.
Et ensuite ils demandent des identifiants AWS en parcourant la liste des répertoires personnels sous lesquels le processus d'un développeur pourrait tourner :
/root/.aws/credentials, /home/ec2-user/.aws/credentials,
/home/ubuntu/.aws/credentials, /home/node/.aws/credentials,
/home/www-data/.aws/credentials, /home/admin/.aws/credentials,
/home/debian/.aws/credentials, /var/www/.aws/credentials,
/usr/src/app/.aws/credentials, /app/.aws/credentials. Puis .aws/config,
.aws/credentials.backup, .aws/credentials.bak, .aws/sso/cache/,
rootkey.csv, aws-exports.js et amplifyconfiguration.json.
Ces chemins dressent l'inventaire d'une machine de développeur, énumérée par nom d'utilisateur, et Vite n'est que la porte. Le bogue est accessoire ; trois bogues plus anciens de la même route voyagent dans les mêmes requêtes. Les opérateurs parient qu'un processus à l'écoute sur une adresse routable tourne sous un utilisateur dont le répertoire personnel contient de vraies clés.
Le trafic est déguisé pour survivre à un coup d'œil distrait aux journaux. F5 a
relevé des en-têtes User-Agent falsifiés alternant entre Googlebot/2.1,
ClaudeBot/1.0, GPTBot/1.4, PerplexityBot/1.0, OAI-SearchBot/1.3 et
Amazonbot/0.1, plus des valeurs X-Forwarded-For et X-Real-IP falsifiées
pour franchir les allow-lists d'adresses IP. Les sources se situent dans les
plages 34.x et 35.x de Google Cloud, réparties sur plusieurs régions, menées par
les États-Unis à 17 297 événements, puis la Belgique à 4 407 et les Pays-Bas à
4 011. Ce mois-ci, une ligne de votre journal d'accès qui se prétend un crawler
IA est une preuve bien faible qu'un crawler l'a envoyée.
Deux des recommandations de F5 sont des questions d'architecture
F5 conclut par cinq conseils. Trois sont ordinaires et justes : corriger vers
7.3.2 ou 8.0.5, filtrer /@fs/ en bordure, vérifier les crawlers par DNS inverse
plutôt que de faire confiance à l'en-tête. Les deux autres décrivent une posture
à tenir plutôt qu'une tâche à terminer.
Veillez à ce que les serveurs de développement ne se lient pas à des interfaces externes. Auditez les configurations Docker compose, les règles d'ingress Kubernetes et les groupes de sécurité cloud.
Faites tourner les secrets exposés : si un serveur de développement Vite non corrigé était joignable depuis des réseaux externes en août 2026, considérez les variables .env locales, les identifiants AWS, les jetons d'accès Azure et les fichiers d'état Terraform comme potentiellement compromis.
Le premier vous demande de tenir une promesse sur chaque port, dans chaque
fichier compose, à travers chaque branche, aussi longtemps que vit le projet, à
un moment où ce qui tape npm run dev est souvent un agent plutôt que vous. Le
second demande ce que vous faites ensuite, et répond : faites tourner ce que la
machine pouvait voir.
Ces deux points deviennent plus faciles si le port s'ouvre ailleurs, et si les fichiers que nomme la wordlist ne contiennent rien qui vaille d'être renouvelé.
Où un workspace Bromure place le port
Bromure Agentic Coding exécute les agents de code à l'intérieur d'une VM Linux virtualisée par le matériel sur votre Mac, avec les contrôles de sécurité du côté hôte de cette frontière. Deux d'entre eux répondent à cette campagne.
Le serveur de développement se lie à l'intérieur d'un switch privé. Dans le
mode NAT par défaut, chaque VM de workspace se rattache à un unique switch
logiciel L2 à l'échelle du processus, multiplexé sur une seule interface vmnet,
sur un sous-réseau privé. Ce sous-réseau est 192.168.64.0/24 à moins que votre
propre LAN ne l'utilise déjà, Bromure y fait tourner son propre serveur DHCP, et
chaque workspace conserve une MAC déterministe et un bail stable. Le manuel en
énonce la conséquence : votre Mac peut joindre les VM, votre LAN physique ne les
voit pas, et les connexions entrantes depuis ailleurs sont impossibles à moins de
publier vous-même un service. Un agent qui se lie à 0.0.0.0 dans cette VM s'est
lié à chacune des interfaces qu'il possède, et chacune d'elles fait face à un
switch qui commence et finit sur votre portable. Vous n'avez aucun groupe de
sécurité à auditer, parce que vous n'avez aucune route entrante à sécuriser.
Vous pouvez quand même voir ce qui écoute, et c'est une liste, pas un audit.
Le tableau de bord du workspace porte une carte Listening Ports qui montre chaque
socket joignable de l'extérieur dans l'invité, sous forme de point de terminaison
<IP-VM>:<port> avec copie en un clic. Cela transforme la recommandation n° 2 de
F5 en une carte que vous consultez d'un coup d'œil, rafraîchie depuis l'invité
toutes les secondes et demie, au lieu d'un audit que vous planifiez. Quand vous
voulez vraiment montrer un aperçu au monde, un service vraisemblablement HTTP
reçoit un bouton globe qui publie ce service-là par un tunnel rapide
Cloudflare, derrière une boîte de dialogue de consentement unique. Vous exposez
un service en cliquant dessus, service par service, sur l'hôte, plutôt qu'en
laissant vivre un drapeau dans un fichier compose.
Vous gardez la raison pour laquelle vous aviez atteint --host au départ. Le
sidecar Chromium jetable partage le même segment L2 que la VM du workspace, si
bien que le navigateur intégré charge le serveur de développement de l'agent à
l'adresse de la VM. Pas sur localhost, puisque le navigateur tourne sur une
machine distincte.
Si d'autres machines doivent réellement joindre la VM, le mode Bridged la raccorde à votre LAN physique. Vous réglez cela par workspace dans l'éditeur de workspace, sur l'hôte, et il retombe sur le NAT si l'interface est indisponible au lancement. Vous faites ce choix dans un panneau, pas dans un fichier de configuration que l'agent peut modifier.
Et si vous publiez le service exprès
Parfois vous voulez vraiment l'aperçu sur internet, pour un client ou un collègue. Alors cliquez sur le globe, ouvrez le tunnel, et laissez les scanners le trouver. Descendez la wordlist, entrée par entrée, et regardez ce qui revient.
.env et /proc/self/environ renvoient l'environnement du workspace, et chaque
identifiant qu'il contient est un leurre. Bromure dérive chaque valeur de
substitution de la vraie valeur plus un sel de 32 octets propre à l'installation,
par HKDF-SHA256, en conservant la forme qu'attend un validateur côté client :
une clé Anthropic se lit sk-ant-api03-brm-…, un jeton GitHub est ghp_ suivi
de 36 caractères, GitLab est glpat- suivi de 20. Bromure écrit ces leurres dans
les variables d'environnement et dans ~/.git-credentials,
~/.docker/config.json, ~/.kube/config et les configurations MCP. Les vraies
valeurs n'entrent jamais dans la VM ; elles restent chiffrées sur le Mac, et un
proxy côté hôte substitue chacune d'elles sur le fil au dernier moment, cantonnée
à l'hôte de destination auquel elle appartient.
/home/ubuntu/.aws/credentials est l'entrée la plus aiguisée, parce que
/home/ubuntu est bien le répertoire personnel d'une VM de workspace Bromure. Le
scanner devine juste quant à l'utilisateur qui fait tourner le serveur. Le
fichier n'est pourtant pas là. La configuration AWS de Bromure n'écrit aucun
fichier d'identifiants ; elle écrit ~/.aws/config avec une ligne
credential_process pointant vers un assistant qui sert, par une socket de
l'hôte, votre véritable identifiant de clé d'accès associé à une fausse clé
secrète de quarante caractères, et omet le jeton de session. Les SDK AWS, la CLI
aws, terraform et boto3 reprennent tous cela d'eux-mêmes. Un scanner qui lit le
fichier de configuration obtient le chemin d'un assistant qu'il ne peut pas
appeler.
Prenez quand même la fausse clé secrète et vous aurez pris quelque chose
d'inerte. L'invité signe ses requêtes avec ce leurre, et l'hôte retire la
signature puis re-signe avec la vraie clé au moment de sortir. Une requête qui
atteint AWS par n'importe quelle autre voie échoue avec
InvalidSignatureException. La dernière recommandation de F5 est de traiter
chaque secret local comme compromis et de le renouveler. La ligne correspondante
dans la documentation de Bromure dit l'inverse : puisque seul le leurre a fuité,
le véritable identifiant n'a jamais besoin d'être renouvelé.
Une entrée de la wordlist nomme un fichier qui vaut de l'argent bien réel :
terraform.tfstate. Les fichiers d'état vivent là où vit le dépôt, si bien que
votre liste de dossiers partagés décide de leur exposition. Les dossiers de
l'hôte s'attachent à un workspace comme des montages virtiofs sous
/home/ubuntu/<basename>, plafonnés à huit par workspace, et ce sont les seules
parties du système de fichiers de votre Mac que la VM peut atteindre. Partagez
le dépôt sur lequel l'agent travaille et rien d'autre, et la traversée trouve un
répertoire au lieu d'un disque.
La plupart des histoires de sécurité pour développeurs cette année décrivent quelque chose qui arrive : un paquet, une archive, un fichier de documentation. Ici, rien n'arrive. À la place, 32 000 requêtes par mois demandent à un processus que vous avez lancé de lire des fichiers à voix haute à un inconnu, et l'issue tient à la machine qui fait tourner ce processus et à ce qui se trouve dans son répertoire personnel.
Mettez le serveur de développement de l'agent sur un switch où votre Mac est seul, et remplissez son répertoire personnel de leurres. Installez Bromure Agentic Coding, puis laissez les scanners demander.