Fuite du code source de Claude Code
Anthropic a expédié une source map avec le code à l'intérieur. Les équipes devraient considérer cela comme un échec de publication.
Anthropic a publié @anthropic-ai/claude-code@2.1.88 sur npm avec cli.js.map dans le tarball. J'ai téléchargé le package depuis le registre et je l'ai vérifié moi-même. La source map contenait 4 756 entrées de sources intégrées. En supprimant node_modules, le package exposait toujours 1 906 fichiers appartenant à Anthropic et environ 515 000 lignes de code, presque entièrement en TypeScript ou TSX.
Si une source map est expédiée avec sourcesContent, vous n'avez pas expédié un fichier de débogage inoffensif. Vous avez expédié du code source en JSON.
Au moment où j'ai vérifié, Anthropic avait déjà commencé à nettoyer. La page de version npm était marquée comme dépréciée avec le message Unpublished. Le dépôt GitHub officiel et la documentation d'installation marquent maintenant l'installation npm comme dépréciée et redirigent les utilisateurs vers l'installateur natif. La réponse a été rapide. L'artefact était déjà public.
Des copies et des analyses étaient déjà en cours à ce moment-là. C'est ainsi que se comportent les artefacts publics sur Internet. Une fois que quelque chose d'utile atterrit dans un registre, le nettoyage se fait à la traîne.
Si vous vous intéressez davantage à ce que le code exposé dit de la conception des agents qu'à la fuite elle-même, Shreyansh a écrit un article séparé sur ce que l'architecture de Claude Code nous apprend sur la création d'agents IA de production. Cet article porte sur la partie plus ennuyeuse, l'hygiène de publication, car les échecs ennuyeux causent toujours beaucoup de dégâts.
Ce qui a été expédié
Voici ce que j'ai pu vérifier à partir du package npm, des métadonnées du registre et des pages publiques d'Anthropic :
@anthropic-ai/claude-code@2.1.88 a été publié sur npm en tant que package public.
- Le tarball incluait
cli.js.map aux côtés de cli.js, README.md, LICENSE.md, package.json, bun.lock et sdk-tools.d.ts.
cli.js.map incluait un tableau sourcesContent rempli.
- La carte contenait un total de 4 756 fichiers intégrés.
- En excluant
node_modules, la carte couvrait toujours 1 906 fichiers appartenant à Anthropic.
- 1 888 de ces fichiers étaient des
.ts ou des .tsx.
- La partie appartenant à Anthropic de la carte contenait environ 515 000 lignes.
- La page npm a ensuite marqué la version comme dépréciée avec le message de l'auteur
Unpublished.
- Le dépôt et la documentation d'installation d'Anthropic marquent maintenant l'installation npm comme dépréciée.
Je m'abstiens délibérément de reproduire du code de la carte ou de lier vers des dépôts miroirs. Il y a déjà suffisamment de bruit public à ce sujet. Ce package exposait bien plus qu'un binaire CLI.
Pourquoi c'est important
Les gens parlent encore des source maps comme s'il s'agissait de restes inoffensifs. Parfois, ils le sont. Les source maps peuvent présenter un faible risque lorsqu'elles restent à l'intérieur du suivi d'erreurs privé et omettent la source originale. Une carte publique avec sourcesContent est une publication de code source.
Ce qui m'a le plus dérangé, c'est à quel point ce mode d'échec est ordinaire. La carte n'expliquait pas seulement les traces de pile. Elle exposait la structure interne, le câblage des prompts, la logique de routage, les chemins de télémétrie, le mécanisme des indicateurs de fonctionnalités et les choix d'orchestration. Je garde cette description de haut niveau à dessein. Je ne veux pas transformer un article sur la sécurité en une visite guidée du code d'une autre personne.
Pour un produit de codage IA, ce type de fuite réduit le coût de l'examen minutieux, de l'imitation et de la planification d'attaques. La rétro-ingénierie d'un CLI groupé prend du temps. Lire une source map avec le code déjà intégré prend quelques minutes.
Même famille, cause différente
J'ai écrit la semaine dernière sur le compromis Telnyx PyPI. Celui-ci était malveillant. Celui-ci ressemble à une erreur d'ingénierie de publication. Opérationnellement, ils se ressemblent.
Je reviens toujours à une phrase : l'artefact est le périmètre.
Les équipes consacrent la majeure partie de leur énergie au code applicatif et aux contrôles d'exécution, puis traitent le package, l'image de conteneur, l'action GitHub, le chart Helm et le bundle de navigateur comme des détails d'emballage. Les attaquants ne font pas cette distinction. Les accidents non plus.
Nous avons vu le même schéma dans la backdoor xz, les compromissions d'actions GitHub, les voleurs d'identifiants PyPI, les mises à jour npm malveillantes, les couches de conteneurs exposées et maintenant un package npm public qui transportait son propre arbre source sous forme de JSON. Les modes d'échec changent. La frontière de confiance ne change pas. Tout ce que vous expédiez devient la chose que les gens inspectent, mirent, comparent, installent et attaquent.
Comment éviter que cela ne se produise
Éviter cela n'est pas glamour. C'est une discipline de publication de base, ce qui explique exactement pourquoi cela fonctionne.
1. Ne pas publier de source maps avec source intégrée
Si vous expédiez un package npm fermé, les source maps publiques doivent être désactivées, sauf si vous êtes à l'aise avec la publication du code qu'elles contiennent. Le débogage privé est acceptable. sourcesContent public est un événement de publication.
Pour les builds frontend et CLI, cela signifie généralement :
- désactiver les source maps publiques pour le package
- générer des cartes cachées et les télécharger vers un suivi d'erreurs privé
- utiliser des cartes sans source si vous avez besoin de symboles sans expédier de code
- examiner les valeurs par défaut du bundler chaque fois que vous modifiez la chaîne d'outils de build
2. Faire de npm pack une porte de sortie de publication stricte
Ne faites pas confiance au dossier dist/. Inspectez le tarball que vous êtes sur le point de publier.
Chaque pipeline de publication doit construire le package, exécuter npm pack, décompresser le tarball et échouer si le contenu dérive en dehors de la politique. Au minimum, échouer la publication lorsque :
- un fichier
.map contient sourcesContent
- un package inclut des fichiers en dehors d'une liste blanche
- le tarball transporte des documents internes, des prompts, des fixtures ou des configurations qui n'ont pas leur place dans le package
- le manifeste change sans révision explicite
Une porte de sortie simple vaut mieux que de découvrir le problème sur X :
npm pack
tar -xzf *.tgz
node -e 'const fs=require("fs"); const map=JSON.parse(fs.readFileSync("package/cli.js.map","utf8")); if (Array.isArray(map.sourcesContent) && map.sourcesContent.some(Boolean)) { console.error("Refus de publier des source maps intégrées"); process.exit(1); }'
3. Publier à partir d'un répertoire propre et autorisé
De nombreuses fuites se produisent parce que les équipes publient depuis la racine d'un monorepo ou depuis un répertoire dist/ qui s'est développé par habitude. Construisez dans un répertoire de publication propre. Copiez uniquement ce qui appartient au package. Utilisez le champ files dans package.json comme liste blanche. Traitez .npmignore comme un filet de sécurité, pas comme le plan.
4. Traiter les actifs IA opérationnels comme sensibles à la publication
Les équipes IA protègent généralement les poids, les clés API et les données clients. Elles deviennent beaucoup plus laxistes avec les prompts, la logique de routage, le comportement de repli, les commutateurs de télémétrie, les indicateurs de fonctionnalités internes et les permissions des outils. C'est une erreur.
Même lorsque ces actifs ne sont pas secrets au sens légal, ils portent toujours une valeur produit et une valeur d'attaque. Si un artefact de publication les inclut, supposez qu'ils seront lus.
5. Vérifier ce que le registre sert après la publication
Même les bonnes pipelines CI manquent des choses. Téléchargez la version exacte que vous venez de publier depuis le registre ou un miroir, inspectez-la à nouveau et alertez en cas de dérive. Si quelque chose passe à travers, les minutes comptent.
Gardez les artefacts de débogage privés par défaut. Les source maps appartiennent beaucoup plus souvent aux flux d'observabilité privés qu'aux registres de packages publics.
Notre biais chez Kolsetu
Nous construisons pour des industries réglementées, nous ne pouvons donc pas prétendre que l'ingénierie de publication se situe en dehors du modèle de sécurité. Un package, un conteneur ou un bundle de navigateur peut être téléchargé, mis en miroir, indexé et recherché en quelques minutes. Cette hypothèse change la façon dont vous publiez des logiciels.
Notre posture par défaut est simple :
- inspecter l'artefact final, pas seulement le dossier qui l'a produit
- garder les actifs de débogage privés
- expédier depuis un répertoire de publication autorisé
- supposer que tout artefact public devient lisible immédiatement
Je pense que beaucoup d'équipes IA sous-estiment encore la discipline de publication car les modèles sont plus amusants à discuter, même si l'emballage est l'endroit où se produisent de nombreux dégâts évitables.
Pensée finale
Ce qui s'est passé ici est embarrassant pour Anthropic. C'est aussi utile pour le reste de l'industrie. Un package npm public est un canal de divulgation, et une source map avec sourcesContent est du code source. Les équipes qui construisent des produits IA passent un temps infini sur les modèles, les prompts, les évaluations et les outils, puis se précipitent dans la dernière ligne droite de l'emballage. Cette dernière ligne droite décide de ce que le monde peut réellement lire.
La prochaine série d'échecs de sécurité IA ne proviendra pas uniquement du comportement des modèles. Certains proviendront de CI, de registres, de conteneurs, de bundles de navigateurs, d'actions GitHub et de sorties de build que personne n'a examinées assez attentivement. Le modèle fait les gros titres. L'artefact décide de ce que le monde peut voir.
Références