Le 19 août 2026, le célèbre pont cross-chain Allbridge a subi une attaque qui a entraîné le vol d'environ $190,000. Cependant, l'attaque elle-même n'a pas été menée en un seul jour: l'attaquant l'a préparée pendant près d'un mois. Nous analysons en détail le mécanisme de cette attaque et comment une faille dans la vérification des messages cross-chain a permis à l'attaquant de faire passer un transfert d'USDC inexistant pour un transfert réel.
Ce qu'il faut savoir au préalable
Pour comprendre comment l'attaque a été menée, il faut d'abord comprendre le fonctionnement du protocole CCTP de Circle et le système de transmission de messages entre blockchains qu'il utilise.
Un transfert ordinaire via CCTP passe par plusieurs étapes. D'abord, le TokenMessenger sur le réseau source brûle de l'USDC. Ensuite, le MessageTransmitter de Circle vérifie l'authenticité du message et le transmet. Après cela, le TokenMessenger sur le réseau de destination reçoit le message, le vérifie et crée la quantité correspondante d'USDC. Enfin, le Router, après avoir confirmé la réception effective des fonds, transfère l'USDC à l'utilisateur.
La transmission des messages est assurée par le contrat Circle MessageTransmitterV2. Il émet une attestation pour le message complet - une preuve signée par Circle qu'un message cross-chain donné a bien été vérifié et authentifié. Cependant, cette attestation indique seulement que le contenu du message a été certifié par Circle. À elle seule, elle ne prouve pas que le montant indiqué dans le message a réellement été transféré.
La création de tokens sur le réseau de destination est assurée par Circle TokenMessengerV2. Après que MessageTransmitterV2 reçoit le message, il détermine quel contrat doit être appelé, en se fondant sur l'adresse du destinataire indiquée dans l'en-tête du message. Dans une opération CCTP normale, cette adresse doit correspondre au contrat TokenMessengerV2 sur le réseau de destination. Ensuite, le TokenMessenger source, le token, le montant et l'adresse du destinataire sont vérifiés, et ce n'est qu'après avoir passé avec succès toutes les vérifications que de nouveaux USDC sont créés.
Le module CCTP dans l'infrastructure d'Allbridge se situe plus loin dans cette chaîne. Il accepte les dépôts terminés et les transforme en enregistrements que le Router peut reconnaître, après quoi celui-ci transfère les tokens à l'utilisateur. C'est justement ici qu'apparaît un détail d'une importance fondamentale.
À ce stade, il devient clair que la fonction sendMessage de Circle est une interface universelle. N'importe quel utilisateur peut l'appeler et transmettre un fragment de contenu de message cross-chain, que Circle authentifie ensuite. Le simple fait d'appeler cette interface ne conduit automatiquement ni à la combustion d'USDC ni à la création de nouveaux USDC. Un transfert CCTP ordinaire requiert en plus la participation du TokenMessenger sur le réseau source. Il brûle d'abord de l'USDC, puis crée un message contenant des informations sur les tokens détruits. Dans l'attaque examinée, l'attaquant a contourné cette étape: il a simplement formé un message cross-chain sans brûler aucun USDC.
La cause première de la vulnérabilité
Dans le contrat Allbridge CCTPTokenMessenger, la fonction receiveCctpMessage, destinée à recevoir les messages cross-chain, ne vérifiait pas si le champ sender de l'en-tête du message CCTP correspondait à l'adresse du TokenMessenger distant. Le champ recipient n'était pas non plus vérifié par rapport au contrat Circle TokenMessengerV2.
En conséquence, MessageTransmitterV2.receiveMessage transmettait le message cross-chain reçu au contrat attaquant, lui permettant de déterminer de fait comme si les tokens avaient été créés avec succès. En même temps, le contrat d'Allbridge lui-même ne vérifiait pas en plus si le solde en USDC du Router avait réellement augmenté après la prétendue création de tokens. Au lieu de cela, il faisait confiance au montant contenu dans le message que l'attaquant avait lui-même formé, et l'enregistrait comme solde disponible à recevoir. Ce montant était stocké dans la valeur receivedTokenAmount associée au messageHash à l'intérieur du hookData du message cross-chain.
Il n'y avait pas non plus de protection supplémentaire dans le hookData. Lorsque le Router effectue un versement, il recalcule lui-même le messageHash à partir des paramètres de l'appel, puis recherche l'enregistrement interne de dépôt précédemment créé pour ce hash. Avant même d'envoyer le message à Polygon, l'attaquant pouvait calculer lui-même le hash requis pour ces mêmes paramètres et enregistrer à l'avance le messageHash dans le hookData du message cross-chain. Ainsi, l'enregistrement que le Router trouvait ensuite était un enregistrement interne créé par l'attaquant lui-même et n'avait aucun rapport avec la réception effective des fonds.
En conséquence, l'attaquant a pu appeler directement le sendMessage du contrat Circle MessageTransmitterV2 sur le réseau Polygon et former un message cross-chain arbitraire. Après que Circle a signé ce message, l'attaquant a pu passer avec succès la vérification de l'attestation sur le réseau Base. En conséquence, le faux message a été perçu comme un véritable dépôt cross-chain, après quoi le Router a transféré les tokens à l'adresse indiquée par l'attaquant.
Comment l'attaque contre Allbridge a été menée étape par étape
1. Le 26 juillet 2026, l'attaquant a pour la première fois appelé directement la fonction sendMessage du contrat Circle MessageTransmitterV2 sur le réseau Polygon. Il s'agissait d'une opération ordinaire d'envoi d'un message cross-chain. La transaction a créé un événement MessageSent, mais aucune combustion réelle d'USDC n'a eu lieu. Circle a ensuite émis une attestation pour le message complet, et cette étape s'est déroulée normalement, exactement comme le prévoit le protocole.
Des données dans un format caractéristique de CCTP ont été placées dans le message. Le réseau source indiqué était Polygon, le réseau de destination Base, et le montant déclaré était de 1,000,000 USDC. Le paramètre feeExecuted était fixé à zéro, et destinationCaller pointait vers le contrat Allbridge CCTPTokenMessenger.
En même temps, l'attaquant a défini son propre contrat comme recipient dans l'en-tête du message, a indiqué dans le corps du message l'adresse du Messenger distant configuré comme sourceSender, et a placé le messageHash du Router calculé à l'avance dans le hookData. Tous ces paramètres avaient été préparés de manière à passer par la suite les vérifications d'Allbridge.
2. Après avoir créé le message cross-chain malveillant, l'attaquant a attendu environ 24 jours. La raison de cette attente tenait aux particularités du fonctionnement du Router sur le réseau Base. Comme il assure la fonction de réacheminement des fonds, il ne conserve généralement pas un volume important de liquidité pendant longtemps.
Ce n'est que le 19 août 2026, lorsque le relayer d'Allbridge venait de créer environ 191,112 USDC à la suite d'un véritable dépôt CCTP d'un autre utilisateur, que le solde du Router a atteint environ 191,156 USDC.
Ces fonds appartenaient à de vrais utilisateurs et représentaient des transferts cross-chain en attente d'être envoyés à leurs destinataires. L'attaquant a attendu cette très courte période où le Router détenait suffisamment de liquidité pour réaliser son plan, et a lancé l'attaque directe seulement six secondes après l'arrivée du véritable dépôt.
3. Le contrat attaquant a d'abord appelé la fonction receiveCctpMessage du contrat CCTPTokenMessenger, en transmettant le message et les données de signature (attestation) obtenues lors de la transaction précédente sur Polygon.
Les vérifications de destinationCaller et sourceSender ont été passées avec succès, puisque les deux valeurs avaient été choisies et formées à l'avance par l'attaquant lui-même. Ensuite, le contrat attaquant a appelé la fonction receiveMessage du contrat Circle MessageTransmitterV2.
Dans le cadre de cette fonction, un rappel (callback) vers le contrat attaquant a été exécuté, puisque c'était précisément lui qui était indiqué dans le champ recipient de l'en-tête du message. Le contrat attaquant a simplement renvoyé un résultat réussi, sans effectuer l'opération de création de tokens attendue via le Circle TokenMessenger.
Allbridge n'a pas non plus revérifié le solde du Router et ne s'est pas assuré que le contrat appelé était réellement le Circle TokenMessengerV2. Au lieu de cela, il a directement enregistré la valeur amount - feeExecuted dans receivedMessages[messageHash]. Ainsi, à l'intérieur du système est apparu un enregistrement de prétendument 1,000,000 USDC reçus, alors qu'aucun dépôt correspondant n'existait.
4. Comme le message cross-chain créé à l'avance par l'attaquant indiquait un montant de 1,000,000 USDC, alors que le solde du Router à ce moment-là n'était que d'environ 191,156 USDC, il manquait à l'attaquant environ 808,844 USDC pour effectuer le transfert ultérieur.
Pour augmenter temporairement le solde du Router jusqu'à la valeur requise, l'attaquant a utilisé un prêt flash (flash loan) d'Aave. Cela lui a permis d'emprunter 808,844 USDC le temps d'une seule opération et de porter le solde du Router au montant indiqué dans le faux message. Après cela, les conditions du retrait ultérieur des fonds étaient réunies.
5. Ensuite, l'attaquant a appelé la fonction receiveToken du Router pour effectuer l'opération de règlement. À partir des paramètres de l'appel, le Router a recalculé lui-même le hash et a obtenu une valeur qui correspondait entièrement au messageHash que l'attaquant avait calculé à l'avance et placé dans le hookData.
Après cela, le Router n'a vérifié qu'une seule chose: s'il existait dans le contrat CCTPTokenMessenger un enregistrement receivedTokenAmount correspondant à ce messageHash et s'il dépassait zéro. La présence d'un tel enregistrement a été de fait perçue comme la preuve qu'un véritable dépôt avait été reçu. Comme le Router retient une commission de 0.1%, après l'avoir déduite, il a directement transféré les 999,000 USDC restants au contrat attaquant.
Ainsi, tout au long de l'opération, le Router n'a vérifié que la présence d'un solde de crédit interne correspondant dans le contrat CCTPTokenMessenger. Il n'a pas revérifié si ce crédit correspondait à une entrée réelle d'actifs sur la blockchain pour un montant équivalent.
6. Après avoir reçu 999,000 USDC, l'attaquant a remboursé à Aave le principal du prêt flash - 808,844 USDC - et a payé environ 404.422012 USDC de commission pour son utilisation.
La plus grande partie des pertes a porté sur de véritables dépôts cross-chain qui venaient d'arriver au Router et n'avaient pas encore été transférés à leurs destinataires légitimes. Fait notable, les 1,000 USDC de commissions du Router mentionnés plus haut ont également été volés par la suite par d'autres attaquants qui ont reproduit la même méthode d'attaque.
Le problème de l'attestation
La cause principale de l'attaque a été la vérification insuffisante du message cross-chain de la part d'Allbridge. Une attestation Circle prouve seulement que le contenu du message n'a pas été modifié après son authentification. Elle ne prouve pas que le message résultait réellement de la combustion de tokens sur le réseau source ou de leur création sur le réseau de destination.
Allbridge a directement fait confiance au montant, à l'adresse d'origine des fonds et au messageHash que l'attaquant avait lui-même formés dans le message CCTPTokenMessenger. Ces données ont été enregistrées comme solde disponible au retrait et sont de fait devenues perçues par le système comme la taille réelle du dépôt.
Pour les systèmes de ponts cross-chain, le principe clé est le suivant: un message correctement authentifié et vérifié est une condition nécessaire pour effectuer un règlement inter-réseaux, mais le fondement du versement final du Router doit être la réception effective des actifs.
