Le backward pass de PyTorch peut dissimuler des malwares Turing-complets dans des termes à perte nulle
Des chercheurs démontrent comment les particularités de la précision en virgule flottante permettent l'exécution de code arbitraire au sein de la descente de gradient de PyTorch, même lorsque les métriques de perte indiquent zéro.
Traduit automatiquement depuis l'original anglais.
Une nouvelle démonstration technique révèle que le moteur de différentiation automatique de PyTorch peut être trompé pour exécuter des programmes arbitraires lors du backward pass (rétropropagation) de l'entraînement. En exploitant les divergences entre l'arithmétique en virgule flottante IEEE 754 et le calcul symbolique, un attaquant peut intégrer une machine à états Turing-complète, telle que le Jeu de la Vie de Conway, dans les poids du modèle. Cela se produit alors que la perte rapportée reste exactement à zéro, échappant ainsi aux contrôles standard de surveillance et de validation.
Ce qui s'est passé
La découverte provient d'une enquête sur les anomalies de précision en virgule flottante au sein de PyTorch. Le chercheur cherchait initialement à déterminer si une fonction de perte pouvait s'évaluer mathématiquement à zéro tout en déclenchant des mises à jour des poids durant la descente de gradient. Le résultat a confirmé qu'il est possible de construire un terme de perte qui s'affiche comme 0.0 dans toutes les métriques d'entraînement tout en forçant l'optimiseur à exécuter une logique complexe. Cette trouvaille transforme une curiosité numérique théorique en un vecteur d'attaque viable contre la chaîne d'approvisionnement des pipelines d'apprentissage automatique.
Le modèle de menace implique un développeur effectuant un fine-tuning d'un modèle open-source, tel que Llama-3-8B de Meta. Les pratiques de sécurité standard peuvent inclure la vérification des empreintes SHA-256 des fichiers de checkpoint et la revue du code Python pour détecter les backdoors évidents ou les appels système. Si les courbes d'entraînement semblent normales et que les pertes auxiliaires restent plates, l'environnement est généralement considéré comme sûr. Cependant, un attaquant peut distribuer un paquet malveillant, tel qu'un faux régulariseur nommé UltraLoss, qui s'intègre parfaitement dans la boucle d'entraînement sans modifier le checkpoint de base, l'architecture ou le jeu de données.
Lorsque ce terme de perte malveillant est ajouté à la perte totale, il rapporte 0.000000 à chaque itération. Malgré cette apparence bénigne, l'appel à total_loss.backward() et optimizer.step() exécute un programme arbitraire intégré dans les poids du modèle. L'attaquant n'a pas besoin de muter directement les paramètres lors du forward pass, rendant l'exploit difficile à détecter par l'analyse statique standard ou la journalisation runtime des valeurs de perte.
Comment cela fonctionne
L'exploit repose sur le désaccord entre la troncature en virgule flottante au niveau matériel et les règles de différentiation symbolique utilisées par les moteurs autodiff. Le mécanisme central utilise une fonction h(u) = (2^30 + u) - 2^30. Dans l'arithmétique float32 IEEE 754, ajouter une petite valeur u (où |u| < 64) à 2^30 entraîne un arrondi de retour à 2^30, car l'écart entre les nombres représentables à cette magnitude est de 128. Soustraire ensuite 2^30 donne 0.0. Toutefois, le moteur autograd de PyTorch traite l'addition et la soustraction symboliquement, enregistrant leurs dérivées comme étant égales à 1. Ainsi, bien que le forward pass voie zéro, le backward pass calcule un gradient de 1.
Pour créer une source de gradient furtive, le chercheur combine ce comportement avec la règle du produit. Une perte scalaire est construite en multipliant deux termes : l'un qui évalue au vecteur de gradient cible dans le backward pass mais à zéro dans le forward pass, et l'autre qui est zéro dans les deux passes mais dont la dérivée est de 1. Spécifiquement, la perte est définie comme la somme de (v - h(v)) * h(theta), où v est la mise à jour de poids souhaitée. Dans le forward pass, h(theta) est zéro, donc la perte est zéro. Dans le backward pass, la règle du produit permet à la valeur forward sauvegardée du premier terme de circuler comme gradient, définissant efficacement theta.grad au vecteur de mise à jour souhaité.
Ce mécanisme permet à l'optimiseur d'écraser les poids avec l'état suivant d'un automate cellulaire, tel que le Jeu de la Vie de Conway, à chaque étape d'entraînement. Le chercheur a démontré cela en câblant les règles du Jeu de la Vie dans 1 024 poids d'un CNN entraîné sur MNIST. Sur 2 345 étapes, la perte auxiliaire est restée à zéro, le modèle a atteint une précision normale, et les poids ont simulé avec succès l'automate sans erreur. Les valeurs de mise à jour sont de petits entiers (-1, 0, 1), qui ne subissent aucune erreur d'arrondi en float32, garantissant des transitions d'état précises.
Détails clés
- L'exploit fonctionne car IEEE 754
float32arrondit les petites additions à de grandes constantes à zéro, tandis que l'autograd de PyTorch calcule les dérivées symboliquement comme étant égales à 1. - Une fonction de perte peut être construite pour s'évaluer à
0.0dans le forward pass tout en produisant un vecteur de gradient arbitraire dans le backward pass. - L'attaque permet à des programmes Turing-complets, tels que le Jeu de la Vie de Conway, de s'exécuter dans les poids du modèle lors des mises à jour SGD standard.
- La logique malveillante peut être cachée via le « math-washing », où les règles des automates cellulaires sont déguisées en régulariseurs géométriques ou en couches convolutionnelles.
- Les attaquants peuvent stocker des constantes critiques, telles que les poids des noyaux pour la machine à états, dans des fichiers de configuration externes présentés comme des résultats de réglage des hyperparamètres.
- Les extensions CUDA compilées peuvent davantage obscurcir la logique, enveloppant du code binaire malveillant dans de fines classes Python qui semblent être des pénalités spectrales standard.
Pourquoi c'est important
Cette vulnérabilité remet en question l'hypothèse selon laquelle la surveillance des métriques de perte et la vérification des empreintes de fichiers suffisent à sécuriser les pipelines d'entraînement ML. Les développeurs font souvent confiance aux bibliothèques open-source et aux techniques de régularisation sans inspecter profondément leur implémentation mathématique. Si une bibliothèque prétend améliorer la convergence ou la stabilité, ses opérations internes sont rarement auditées pour des comportements de gradient non standards. Cet exploit montre qu'une bibliothèque peut se comporter parfaitement normalement en termes de métriques de sortie tout en détournant le processus d'entraînement lui-même.
Pour les équipes développant des produits avec l'IA, cela met en évidence un angle mort dans la sécurité de la chaîne d'approvisionnement. La sécurité logicielle traditionnelle se concentre sur l'exécution de code et l'accès aux données, mais l'entraînement ML introduit un nouveau vecteur où l'algorithme d'optimisation lui-même devient le porteur de charge utile. Puisque le code malveillant s'exécute au sein des opérations mathématiques légitimes de la descente de gradient, il contourne de nombreuses protections conventionnelles. Cela nécessite un changement dans la façon dont les ingénieurs valident les composants ML tiers, allant au-delà des métriques superficielles pour vérifier l'intégrité mathématique des fonctions de perte.
Ce que vous pouvez faire
- Auditez toute fonction de perte personnalisée ou régulariseur pour repérer les opérations impliquant de grandes constantes et de petits décalages, ce qui peut indiquer une exploitation en virgule flottante.
- Vérifiez que les gradients calculés lors de la rétropropagation correspondent aux dérivées mathématiques attendues, plutôt que de se fier uniquement aux valeurs de perte.
- Inspectez les fichiers de configuration et les actifs externes chargés par les bibliothèques ML pour détecter des constantes ou des noyaux inexpliqués qui ne correspondent pas aux objectifs documentés.
- Préférez l'utilisation d'extensions compilées provenant de sources fiables et vérifiez leur intégrité, car elles peuvent masquer la logique malveillante plus efficacement que le code Python.
- Implémentez des vérifications runtime comparant les mises à jour des poids aux normes attendues, signalant les motifs inhabituels même si la perte reste stable.
- Traitez les paquets ML tiers avec la même rigueur que les dépendances système, en reconnaissant qu'ils peuvent exécuter une logique arbitraire pendant l'entraînement.



