SToFU Systems · Analyse d’incident · 20 octobre 2026
Sommaire
- Tout a commencé par une demande de développement
- Téléchargement et inspection des fichiers
- Comment le hook Git post-checkout pouvait s’exécuter
- Ce que fait le téléchargeur du hook Git
- Une application était-elle cachée dans l’archive ?
- Ce que le serveur de téléchargement a renvoyé
- Aurait-il pu s’agir d’un utilitaire légitime ?
- Examiner un dépôt Git inconnu
- Après l’examen de l’archive
- Correspondance et fichiers de preuve
Tout a commencé par une demande de développement
Le premier message est arrivé par notre site web le 15 octobre 2026. Son expéditeur souhaitait de l’aide pour développer une plateforme de détection de la fraude financière. Le système proposé devait évaluer le risque des transactions et utiliser l’analyse comportementale, avec notamment des exigences de vérification par blockchain et de production de rapports.
Le 19 octobre, nous avons reçu le lien de téléchargement. Le courriel qui l’accompagnait nous orientait vers la branche conf pour l’architecture et la branche NDA pour l’accord. Il réitérait la demande d’examiner et de signer l’accord de confidentialité.
Please review the project materials and review and sign the NDA in the NDA branch.
Suivre ces instructions amenait la personne chargée de l’examen à extraire l’archive, puis à changer de branche dans Git. Le courriel présentait ces deux opérations comme des étapes de la lecture de la documentation. Il ne mentionnait pas l’exécution d’un programme téléchargé.
Le courriel contenant l’archive du projet et les instructions pour ouvrir la branche NDA. Les informations permettant une identification sont recouvertes de rectangles gris.
Téléchargement et inspection des fichiers
Le lien menait à une page classique de partage de fichiers Dropbox. Nous avons téléchargé AI-Fraud-Detection_Blockchain.tar.gz dans un environnement d’examen isolé et conservé l’archive d’origine comme référence. L’URL de partage précise n’est pas divulguée ici.
Nous avons répertorié le contenu de l’archive et lu directement les objets Git fournis. Cela nous a permis de récupérer les documents des trois branches sans extraire de branche dans l’arbre de travail ni exécuter le code fourni. Dans les arbres des branches, nous avons trouvé 15 fichiers Markdown et un document Word.
| Branche | Fichiers | Ce que nous avons trouvé |
|---|---|---|
master |
8 fichiers Markdown | Un README, une présentation du projet, les exigences du produit et des cas d’usage métier. D’autres documents portaient sur les performances, la sécurité, les tests et l’exploitation. |
conf |
7 fichiers Markdown | Des consignes pour une proposition de développement, l’architecture et l’intégration de la blockchain, les exigences des contrats intelligents, la conception des données et des API, un moteur de risque fondé sur l’IA et les jalons de livraison. |
NDA |
1 fichier DOCX | Un accord de confidentialité avec un bloc de signature et des champs de modèle à remplir. |
Le produit proposé combinait l’analyse des transactions, des règles de détection de fraude et des scores d’apprentissage automatique avec une vérification par blockchain. La pile suggérée utilisait Node.js et TypeScript avec Express, PostgreSQL, des bibliothèques Python d’apprentissage automatique et Ethereum. Le document de livraison prévoyait six jalons sur 24 semaines. Nous avons trouvé des documents de planification dans l’ensemble des arbres fournis, sans implémentation de l’application, modèle entraîné ni code source de contrat intelligent à examiner.
Certains détails méritaient un examen plus attentif. Les exemples d’API contenaient les chaînes littérales <built-in function id> et <built-in function hash> dans les chemins des points de terminaison. L’accord de confidentialité contenait encore des champs de modèle à remplir. Ces incohérences soulevaient des questions sur le soin apporté à la préparation des documents.
Le fichier exécutable .git/hooks/post-checkout constituait une découverte plus préoccupante. Ses commentaires décrivaient un utilitaire de mise à jour de navigateur ou d’extension, sans lien apparent avec l’examen du projet. La lecture du script a révélé des instructions visant à télécharger un programme externe et à le lancer en arrière-plan. La demande de changement de branche du courriel pouvait conduire une personne vers ce chemin d’exécution alors qu’elle cherchait à lire l’accord de confidentialité.
Nous avons maintenu le dépôt inactif et examiné le hook comme du texte. Les métadonnées pertinentes de l’archive et le comportement du script sont présentés ci-dessous.
Comment le hook Git post-checkout pouvait s’exécuter
Le fichier AI-Fraud-Detection_Blockchain.tar.gz mesure 779 429 octets. Ses 100 entrées TAR comprennent 60 fichiers ordinaires. Un répertoire .git complet était livré avec les documents.
Le répertoire des hooks contenait les fichiers .sample habituels ainsi qu’un exécutable nommé post-checkout.
AI-Fraud-Detection_Blockchain/.git/hooks/post-checkout
Il ne porte pas le suffixe .sample. Son mode TAR est 0777, ce qui inclut les permissions d’exécution, et sa taille est de 2 774 octets.
Git invoque post-checkout après avoir mis à jour l’arbre de travail au moyen d’opérations telles que checkout ou switch, à condition que l’environnement autorise l’exécution du hook. La documentation de Git décrit ce déclenchement.
Pourquoi le répertoire .git archivé est important
Un git clone ordinaire ne copie pas les hooks locaux côté client du dépôt source, comme l’explique Pro Git. Cette livraison contenait le répertoire .git existant dans une archive : le hook local était donc livré avec lui.
Le chemin, le mode et la taille du hook lus directement dans le TAR d’origine. Nous n’avons pas utilisé le répertoire reçu comme dépôt Git.
Nous avons inspecté directement le conteneur et les objets Git, sans exécuter checkout ni switch sur le dépôt reçu.
Ce que fait le téléchargeur du hook Git
Les commentaires du script shell décrivent un utilitaire de mise à jour de navigateur ou d’extension. Nous n’avons trouvé aucune exigence concernant un tel utilitaire dans les documents du projet. Le script est en texte clair, sans obfuscation.
Le seuil de taille inutilisé
Le script définit THRESHOLD à 100 et demande à Git une liste des noms de fichiers modifiés. Il initialise TRIGGER à zéro.
THRESHOLD=100
FILES=$(git diff --name-only "$OLD_HEAD" "$NEW_HEAD")
TRIGGER=0
Dans la boucle, il calcule SIZE. Aucune comparaison avec THRESHOLD n’est effectuée et aucune affectation ne modifie TRIGGER. Le bloc de téléchargement s’exécute lorsque TRIGGER vaut zéro.
if [ "$TRIGGER" -eq 0 ]; then
Dans le déroulement normal de ce script, la condition est vraie même lorsque la liste des fichiers modifiés est vide. Le seuil ne limite pas le téléchargement.
Numéros de ligne d’origine conservés. TRIGGER reste à zéro. THRESHOLD est déclaré, mais jamais utilisé dans une comparaison.
Des téléchargements distincts pour Linux, macOS et Windows
La valeur renvoyée par uname -s détermine le chemin de téléchargement et le nom du fichier local.
| Système détecté | Chemin sur le serveur | Nom du fichier local |
|---|---|---|
| Linux | /api/l |
run-command.sh |
| Darwin / macOS | /api/m |
run-command.sh |
| MINGW, MSYS, CYGWIN, Windows_NT | /api/w |
run-command.cmd |
| Système non reconnu | /api/l |
run-command.sh |
Les URL utilisent un même hôte, remplacé ici par <DOWNLOAD_DOMAIN>. Nous avons conservé le hook non expurgé à titre privé. Les branches conditionnelles couvrent Linux, macOS et Windows, avec un recours à Linux pour un système non reconnu. Nous n’avons pas testé l’exécution sur ces systèmes.
Téléchargement du fichier et tentative d’exécution
Le hook enregistre le fichier dans ${TMPDIR:-/tmp} à l’aide de curl, ou de wget si curl n’est pas disponible. Aucune vérification de signature ni de hachage attendu n’est effectuée avant les instructions d’exécution qui suivent.
chmod +x "$CMD_FILE"
"$CMD_FILE" > /dev/null 2>&1 &
L’esperluette finale lance la commande en arrière-plan. La sortie standard et la sortie d’erreur standard sont toutes deux redirigées vers /dev/null.
Après la tentative d’exécution, le hook écrit azuku dans .git-checker dans le répertoire temporaire. Il ne vérifie jamais la présence de ce marqueur avant de télécharger à nouveau. Il n’attend pas non plus la réussite du processus en arrière-plan avant d’écrire le fichier. Le marqueur pourrait donc exister après une tentative d’exécution infructueuse.
Les instructions d’origine de téléchargement, de chmod, d’exécution en arrière-plan et d’écriture du marqueur. Le programme de deuxième étape ne figure pas dans cet extrait.
Un commentaire vers la fin indique de supprimer le répertoire temporaire de téléchargement. Aucune commande de suppression ne figure en dessous.
Une application était-elle cachée dans l’archive ?
Le téléchargement réseau soulevait une autre question. Une application se trouvait-elle déjà dans l’archive, peut-être dans l’historique Git ou dans l’accord de confidentialité ? Nous avons examiné les limites des conteneurs, puis décodé tous les objets Git fournis et inspecté le contenu du DOCX.
Les limites de l’archive
Nous avons enregistré le SHA-256 de l’archive d’origine avant d’inspecter son contenu.
6f44ff4e461828dd1fe6ede75ca8d9d4b579c2ac223463629e9a7537b9df5040
La décompression de gzip en tant que données a produit un flux TAR de 890 880 octets. Le flux gzip se terminait correctement, sans octet inutilisé après sa fin. Les 5 120 derniers octets après la dernière entrée TAR étaient du remplissage par des zéros.
Nous avons ensuite examiné les fichiers et objets correspondant à ces entrées de conteneur.
Vérifications enregistrées de la fin de flux gzip et du remplissage TAR. Aucun code de l’échantillon n’a été exécuté.
Repérage du hook dans l’en-tête TAR
L’en-tête de l’entrée post-checkout commence à 0xCF600, soit 849 408, dans le TAR décompressé. Les données du fichier commencent à 849 920. Ces décalages se rapportent au flux TAR, et non au fichier .gz compressé.
À ce décalage, l’en-tête commence par le chemin vers post-checkout.
TAR / affichage hexadécimal
000cf600 41 49 2d 46 72 61 75 64 2d 44 65 74 65 63 74 69 |AI-Fraud-Detecti|
000cf610 6f 6e 5f 42 6c 6f 63 6b 63 68 61 69 6e 2f 2e 67 |on_Blockchain/.g|
000cf620 69 74 2f 68 6f 6f 6b 73 2f 70 6f 73 74 2d 63 68 |it/hooks/post-ch|
000cf630 65 63 6b 6f 75 74 00 00 00 00 00 00 00 00 00 00 |eckout..........|
000cf640 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000cf650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000cf660 00 00 00 00 30 30 30 30 37 37 37 00 30 30 30 31 |....0000777.0001|
000cf670 37 35 30 00 30 30 30 31 37 35 30 00 30 30 30 30 |750.0001750.0000|
000cf680 30 30 30 35 33 32 36 00 31 35 32 35 32 30 30 34 |0005326.15252004|
000cf690 33 30 37 00 30 32 34 30 37 35 00 20 30 00 00 00 |307.024075. 0...|
000cf6a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Dans un en-tête TAR, mode occupe les octets [100:108] et size occupe [124:136]. Les champs décodés de cette entrée figurent après le dump.
| Champ TAR | Octets bruts / valeur |
|---|---|
| mode | b'0000777\x00' |
| size | b'00000005326\x00' |
| Mode en octal | 0777 |
| Taille en décimal | 2774 octets |
| Somme de contrôle stockée / calculée | 10301 / 10301 |
La taille en octal correspond à 2 774 octets. La somme de contrôle stockée dans l’en-tête est 10 301. Son recalcul en remplissant le champ de somme de contrôle avec des espaces donne le même résultat.
L’en-tête TAR brut du hook et ses champs décodés. Son nom, ses permissions et sa taille sont visibles dans les octets du conteneur.
Nous avons également calculé le hachage du hook extrait de cette entrée.
854b3b88b06fad9d9ffec36b35be0133b1d502084d4d7cce232eda2b2dd03092
Le dump de l’entrée TAR et le hook anonymisé sont joints à l’article. Le hachage ci-dessus identifie l’original non expurgé conservé à titre privé, et non la copie expurgée destinée à la publication.
Lecture des objets Git sans checkout
Il y a 24 objets non empaquetés dans .git/objects, chacun stocké dans un flux zlib. Les données décompressées contiennent un en-tête Git suivi du corps de l’objet.
<type> <size>\0<body>
Nous avons vérifié la longueur déclarée du corps et calculé le SHA-1 sur l’ensemble de la séquence décodée, y compris l’en-tête et l’octet NUL. Le résultat doit correspondre à l’identifiant d’objet dans le nom du fichier. Cela vérifie l’intégrité de l’objet, sans rien indiquer sur son créateur.
Pour chaque objet, nous avons comparé la longueur déclarée à celle du corps et vérifié le hachage de l’ensemble des données décodées.
expanded = zlib.decompress(compressed_object)
header, body = expanded.split(b"\0", 1)
kind, declared_size = header.decode("ascii").split()
assert len(body) == int(declared_size)
assert hashlib.sha1(expanded).hexdigest() == object_id
Nous avons également vérifié les fins des flux zlib. Les objets se répartissent en 16 blobs, 5 arbres et 3 commits. Le parcours des têtes des trois branches, de leurs commits parents et de leurs arbres enfants permet de retrouver les 24 objets. Aucun blob n’est inaccessible parmi les objets fournis.
Git / relations entre commits
master 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f
tree feb0feaf7b8e826b085e90dea5399772d7b91f02
parent (none)
conf 239b9aa2edc8c5e21fddeea5ed0e937496ae013f
tree 048b51f9673f94354251ce16a78e663c71667a4c
parent 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f
NDA a1311875d86bf6f1a6b9f2fee6527abbd1ce647d
tree cc020d922090835ea4ac3a3e418d0213d7a2ad94
parent 239b9aa2edc8c5e21fddeea5ed0e937496ae013f
L’inventaire complet des objets inclut ceux qui ne figurent pas dans l’arbre de travail courant.
Inventaire des 24 objets Git
| Identifiant d’objet | Type | Corps, en octets |
|---|---|---|
| 08e2cda2f440c1792c7c35a3499bfd1ade3e9bad | blob | 6497 |
| 22bb86aacf377c17c7ad0d52c5cefeeb93dfa13e | blob | 5123 |
| 2a7091bdd006a2f98a8c795fd7d2a04c8ee53056 | blob | 2610 |
| 39e13459086f36bc7c933d4e7b5d249a22db24bd | blob | 3061 |
| 3f50e45c67dee5aac77147a5418afe551e8871be | blob | 2433 |
| 476dc872c6def747dcdac549b67a8dc80948b7e1 | blob | 3191 |
| 5a51550933b593eb65da458bbdd579f85c082dab | blob | 752100 |
| 5e53fd0880963e1767ad23fb8612b76e31f04003 | blob | 2807 |
| 60a7cbff83445488fd34b12de1814dc56c956963 | blob | 2054 |
| 74d479352822f5cc1d03552f517cfb5b2d7aa6d3 | blob | 2281 |
| 84e694473554c8a7c01f038a1b6ef8d9355405f7 | blob | 2033 |
| bb7b5d8bc28c4a6257f7d87a685c61ba16a3789c | blob | 2425 |
| d83c8e0c416766be34276013944f5b94726e8c8f | blob | 2776 |
| dfd0f171bca257780eb0d9e22ba2eda1db9d4b68 | blob | 8402 |
| e3b57e48010fc25fd12e7f5f25e952aca843e537 | blob | 6316 |
| ed325750862eb6cdc92b216258a00a784312d793 | blob | 3062 |
| 239b9aa2edc8c5e21fddeea5ed0e937496ae013f | commit | 213 |
| 4bc26f6c18910ca777c8238d2f88f6e725fcdc3f | commit | 165 |
| a1311875d86bf6f1a6b9f2fee6527abbd1ce647d | commit | 212 |
| 048b51f9673f94354251ce16a78e663c71667a4c | tree | 438 |
| 2cb70db8d9317603cb5f0fee0029b66581a7162e | tree | 104 |
| 61874365e5498a30c8b61ef63bbb1d28b4cf4e22 | tree | 320 |
| cc020d922090835ea4ac3a3e418d0213d7a2ad94 | tree | 57 |
| feb0feaf7b8e826b085e90dea5399772d7b91f02 | tree | 104 |
Longueur et SHA-1 vérifiés sur l’encodage Git d’origine de chaque objet. Les 24 vérifications ont réussi.
Suivre l’accord de confidentialité depuis son arbre jusqu’à ses octets
La branche NDA pointe vers un arbre contenant un seul fichier, Non-Disclosure-Agreement.docx. Une entrée d’arbre Git stocke le mode et le nom du fichier sous forme de texte, suivis d’un NUL et de 20 octets bruts pour l’identifiant du blob. Nous avons analysé l’entrée directement à partir du corps de l’arbre.
Arbre Git / affichage hexadécimal
00000000 31 30 30 36 34 34 20 4e 6f 6e 2d 44 69 73 63 6c |100644 Non-Discl|
00000010 6f 73 75 72 65 2d 41 67 72 65 65 6d 65 6e 74 2e |osure-Agreement.|
00000020 64 6f 63 78 00 5a 51 55 09 33 b5 93 eb 65 da 45 |docx.ZQU.3...e.E|
00000030 8b bd d5 79 f8 5c 08 2d ab |...y.\.-.|
Octets bruts de l’arbre NDA et référence décodée à son blob DOCX.
Cette entrée fait référence au blob suivant.
5a51550933b593eb65da458bbdd579f85c082dab
Après décompression zlib, l’objet commence par blob 752100\0. Juste après l’en-tête se trouvent les octets 50 4b 03 04, la signature PK d’un conteneur ZIP.
Blob Git / après décompression zlib
00000000 62 6c 6f 62 20 37 35 32 31 30 30 00 50 4b 03 04 |blob 752100.PK..|
00000010 0a 00 00 00 00 00 87 4e e2 40 00 00 00 00 00 00 |.......N.@......|
00000020 00 00 00 00 00 00 09 00 00 00 64 6f 63 50 72 6f |..........docPro|
00000030 70 73 2f 50 4b 03 04 14 00 00 00 08 00 87 4e e2 |ps/PK.........N.|
00000040 40 a5 76 12 16 69 01 00 00 7b 02 00 00 10 00 00 |@.v..i...{......|
00000050 00 64 6f 63 50 72 6f 70 73 2f 61 70 70 2e 78 6d |.docProps/app.xm|
00000060 6c 9d 92 c1 4e c3 30 10 44 ef 48 fc 43 94 7b 62 |l...N.0.D.H.C.{b|
Octets de l’objet compressé, en-tête Git décodé et début du DOCX. La longueur et l’identifiant de l’objet ont été vérifiés sur l’objet complet.
Le corps mesure 752 100 octets. Son SHA-256 correspond à celui du DOCX que nous avons enregistré séparément pour analyse.
9d85170d2c0aa7a9b90dfc3855715a31d971bba7abb563e9efa1153fdc15634f
Ces objets permettent de retracer le chemin entre la branche NDA et les octets du document.
Identification des 16 blobs
Quinze blobs se décodent en documents de projet Markdown en UTF-8. Le blob restant est le DOCX ci-dessus. Aucun ne commence par un en-tête PE, ELF ou Mach-O.
| Chemin dans les arbres | Taille, en octets | Type / premiers octets |
|---|---|---|
| 04-solution-proposal-guidance.md | 2054 | Texte UTF-8 · 23 20 44 65 76 65 6c 6f 70 6d 65 6e 74 20 43 6f |
| 06-blockchain-architecture.md | 6497 | Texte UTF-8 · 23 20 42 6c 6f 63 6b 63 68 61 69 6e 20 41 72 63 |
| 07-blockchain-integration-specification.md | 2807 | Texte UTF-8 · 23 20 42 6c 6f 63 6b 63 68 61 69 6e 20 49 6e 74 |
| 08-smart-contract-specification.md | 2610 | Texte UTF-8 · 23 20 53 6d 61 72 74 20 43 6f 6e 74 72 61 63 74 |
| 09-data-and-api-architecture.md | 2776 | Texte UTF-8 · 23 20 44 61 74 61 20 26 20 41 50 49 20 41 72 63 |
| 11-ai-fraud-and-risk-engine.md | 3062 | Texte UTF-8 · 23 20 41 49 20 46 72 61 75 64 20 44 65 74 65 63 |
| 14-deliverables-acceptance-and-milestones.md | 6316 | Texte UTF-8 · 23 20 44 65 6c 69 76 65 72 61 62 6c 65 73 2c 20 |
| Detailed/03-business-and-use-cases.md | 3061 | Texte UTF-8 · 23 20 42 75 73 69 6e 65 73 73 20 52 65 71 75 69 |
| Detailed/05-non-functional-requirements.md | 2033 | Texte UTF-8 · 23 20 4e 6f 6e 2d 46 75 6e 63 74 69 6f 6e 61 6c |
| Detailed/10-security-and-privacy-requirements.md | 2433 | Texte UTF-8 · 23 20 53 65 63 75 72 69 74 79 20 26 20 50 72 69 |
| Detailed/12-testing-and-quality-requirements.md | 2425 | Texte UTF-8 · 23 20 54 65 73 74 69 6e 67 20 26 20 51 75 61 6c |
| Detailed/13-deployment-monitoring-and-operations.md | 2281 | Texte UTF-8 · 23 20 44 65 70 6c 6f 79 6d 65 6e 74 2c 20 4d 6f |
| Intro/01-project-overview.md | 8402 | Texte UTF-8 · 23 20 50 72 6f 6a 65 63 74 20 4f 76 65 72 76 69 |
| Intro/02-product-requirements.md | 3191 | Texte UTF-8 · 23 20 50 72 6f 64 75 63 74 20 52 65 71 75 69 72 |
| Non-Disclosure-Agreement.docx | 752100 | DOCX/ZIP · 50 4b 03 04 0a 00 00 00 00 00 87 4e e2 40 00 00 |
| README.md | 5123 | Texte UTF-8 · 23 20 41 49 20 46 72 61 75 64 20 44 65 74 65 63 |
Les 16 blobs fournis ont été classés. Les arbres contiennent des documents de projet ; aucune implémentation du produit n’a été trouvée.
Nous avons lu les corps textuels en plus de vérifier leurs signatures. Le DOCX était le seul blob non textuel et nécessitait une inspection distincte de son conteneur.
Ouverture du DOCX en tant que ZIP
Le document contient 25 entrées ZIP, composées de 17 parties de fichier et de 8 répertoires. Nous avons lu chaque partie de fichier et vérifié son CRC.
| Partie du DOCX | Taille, en octets | CRC32 |
|---|---|---|
| [Content_Types].xml | 1482 | ec936159 |
| _rels/.rels | 737 | 1f222201 |
| customXml/_rels/item1.xml.rels | 296 | 7a393f74 |
| customXml/item1.xml | 400 | 4ed0e3fe |
| customXml/itemProps1.xml | 327 | 457b4363 |
| docProps/app.xml | 635 | 161276a5 |
| docProps/core.xml | 595 | d5626da7 |
| docProps/custom.xml | 722 | 8d44908d |
| word/_rels/document.xml.rels | 1086 | 22475620 |
| word/_rels/settings.xml.rels | 398 | e5802c0c |
| word/document.xml | 91835 | 4df71596 |
| word/fontTable.xml | 4234 | 2796cccd |
| word/media/image1.png | 712863 | 09063019 |
| word/media/image2.png | 10193 | 3aea21cf |
| word/settings.xml | 4116 | 34faa9ef |
| word/styles.xml | 30020 | b4e9edbd |
| word/theme/theme1.xml | 6329 | ed5975e1 |
Noms, longueurs et valeurs CRC32 des parties du DOCX. Nous avons inspecté les données ZIP et XML sans ouvrir le document dans Office.
La liste des parties ne contient ni vbaProject.bin ni pièce jointe OLE. Deux fichiers PNG contiennent un logo et une image de signature. Nous avons aussi inspecté les relations XML et trouvé une référence à un chemin de modèle bureautique local sur la machine de l’auteur du document. Nous n’avons ni résolu cette référence ni chargé le modèle.
L’image de signature et les champs d’auteur Git ne nous donnent aucun moyen fiable d’identifier l’expéditeur. Les uns comme les autres peuvent être copiés ou remplacés.
Nous n’avons trouvé aucune application distincte ni implémentation du produit dans le contenu fourni. Le hook obtient son programme suivant par le réseau. Notre inspection des conteneurs n’exclut pas toutes les formes possibles d’exploitation ou de stéganographie.
Ce que le serveur de téléchargement a renvoyé
Nous avons récupéré les trois URL exactes en tant que données, sans exécuter les réponses ni suivre les redirections. Le 19 octobre, de 17:29:27 à 17:29:28 UTC, chacune a renvoyé le code HTTP 200. Les trois corps contenaient le même message de 21 octets.
Permanently suspended
Les trois observations enregistrées des points de terminaison. Nous n’avons effectué aucune autre requête vers les URL du téléchargeur pendant la préparation de cet article.
Nous ne disposons d’aucun octet de deuxième étape à soumettre à la rétro-ingénierie. Nous ignorons aussi ce que ces points de terminaison renvoyaient auparavant, à un autre visiteur ou dans d’autres conditions de requête. Le message de suspension ne nous donne aucune explication vérifiée de la raison de la suspension du service.
Le hook tente de télécharger et d’exécuter un fichier externe. Affirmer que des mots de passe, jetons, du code source ou des portefeuilles ont été volés nécessiterait des preuves dont nous ne disposons pas.
Aurait-il pu s’agir d’un utilitaire légitime ?
Un outil interne de mise à jour pourrait se retrouver dans une archive par erreur. Les hooks Git, les processus en arrière-plan et curl ont tous des usages légitimes.
Dans cet envoi, le courriel nous demandait explicitement de passer sur une autre branche. Cette opération pouvait invoquer le téléchargeur fourni, alors que la raison annoncée du changement de branche était la lecture d’un accord. Le courriel ne mentionnait pas l’exécution. Nous n’avons par ailleurs trouvé aucun lien entre un outil de mise à jour de navigateur et le système proposé, et la vérification de taille du script était incomplète.
Nous avons traité cet envoi comme une tentative d’attaque par livraison de code et empêché l’exécution du hook. Réexaminer cette appréciation nécessiterait le code source des fichiers téléchargés et une explication vérifiable de la nécessité, pour un prestataire, de les exécuter afin d’examiner l’accord de confidentialité.
Nous n’avons pas établi l’identité de l’opérateur. L’adresse de l’expéditeur, les métadonnées des commits et les noms dans le document ne suffisent pas à attribuer l’opération.
Schéma d’analyse des étapes d’exécution décrites par le hook fourni.
Examiner un dépôt Git inconnu
Un développeur suivant le courriel pouvait atteindre le déclencheur d’exécution alors qu’il lisait encore les informations sur le projet. Il n’était pas nécessaire de compiler ni de démarrer l’application proposée.
Si vous examinez des envois de clients sur une machine contenant des clés SSH de production ou des jetons cloud, un script inattendu peut avoir accès à ces ressources. Un environnement jetable doit maintenir ces identifiants hors d’atteinte. Les sessions de navigateur sur la machine d’examen méritent la même attention.
L’examen doit inclure le répertoire .git fourni et toute automatisation de l’IDE avant qu’un ingénieur ne commence à utiliser ses commandes habituelles. Les scripts d’installation doivent également être examinés attentivement. Dans les journaux de l’hôte, nous rechercherions Git ou un shell téléchargeant un fichier dans un répertoire temporaire, puis l’exécutant. Un processus curl seul nous en dit beaucoup moins.
Conserver le courriel et l’archive d’origine permet à une autre personne de vérifier ultérieurement ce qui a été livré. Les hachages et les événements de l’hôte aident à établir ce qui s’est passé sur la machine. L’absence de marqueur ne permet pas d’établir qu’un programme ne s’est jamais exécuté.
Le téléchargement ou l’extraction de l’archive peuvent-ils exécuter ce hook ?
Le téléchargement et l’extraction ordinaires n’invoquent pas eux-mêmes le hook post-checkout de Git. Dans cet échantillon, le déclencheur documenté est la mise à jour de l’arbre de travail par Git au moyen de checkout ou de switch, lorsque l’exécution des hooks est autorisée. Nous avons inspecté directement les objets fournis sans invoquer ces opérations.
Après l’examen de l’archive
Nous nous attendions à ce que l’échange suivant porte sur l’architecture et les dates de livraison. Nous avons plutôt répondu au sujet du hook et conservé les éléments pour un examen ultérieur. Nous ne pouvons toujours pas dire ce que faisait le programme distant ni qui l’exploitait. Le hook nous donnait suffisamment de raisons d’interrompre le processus Git demandé.
Depuis plus de cinq ans, SToFU Systems et nos solutions aident les entreprises à protéger leurs systèmes, notamment contre les attaques transmises par la correspondance professionnelle et les supports de développement. Nos audits de sécurité examinent comment le code et les accès peuvent être détournés. Nous proposons aussi des services de rétro-ingénierie lorsqu’une équipe doit comprendre un logiciel inconnu.
Si un dépôt ou un binaire soulève des questions, contactez notre équipe pour un examen technique avant de l’introduire dans votre environnement de développement habituel.
Correspondance et fichiers de preuve
Les quatre messages ci-dessous utilisent des marqueurs de substitution pour les noms de personnes, les adresses, les identités de tiers et les liens permettant une identification. Le reste du texte de chaque nouveau message est conservé. Les citations répétées sont omises, chaque courriel étant présenté séparément. L’adresse IP du service du formulaire web et les adresses de destinataires sans rapport sont également masquées.
1. La première demande par notre site web
Courriel / données identifiantes remplacées
Date: Thu, 15 Oct 2026 12:55:21 +0000
From: SToFU Site Form <TEAM_EMAIL>
To: <TEAM_EMAIL>
Subject: SToFU Systems - Contact by <SENDER_NAME> <SENDER_EMAIL>
Reply-To: <SENDER_NAME> <SENDER_EMAIL>
Time: 2026-10-15T12:55:21+00:00
IP: [redacted]
Page: /contact
Name: <SENDER_NAME>
Email: <SENDER_EMAIL>
Attachments: none
Message:
We are currently developing an AI-powered FinTech fraud detection platform designed to help financial organizations identify suspicious transactions, assess potential risks in real time, and strengthen their fraud prevention and investigation processes.
The planned platform will incorporate AI/ML-based fraud detection, transaction risk scoring, behavioral analysis, configurable fraud-detection rules, blockchain-based verification, automated alerts, investigation support, and reporting and analytics.
We are looking to connect with an experienced technology partner with expertise in blockchain, financial technology, AI/ML, and scalable web platform development to help us bring this product to life.
We would welcome the opportunity to discuss your team’s capabilities, experience, and potential role in the project. The specific scope of your team’s involvement, technical responsibilities, and collaboration model can be determined through our discussion, based on your expertise and recommendations.
If this opportunity aligns with your team’s capabilities and interests, I’d be happy to share the project overview and technical roadmap for an initial review.
---
La première demande par notre site web. Vue anonymisée du courriel conservé, destinée à la publication.
SHA-256 de l’EML privé non expurgé : bf7d0f3a59b84f509ca436e0750640e844e9731ce363a42a99d5be60cdf8597e
2. Notre réponse demandant les documents
Courriel / données identifiantes remplacées
Date: Sat, 17 Oct 2026 19:46:28 -0000
From: <TEAM_MEMBER_NAME> <TEAM_EMAIL>
To: <SENDER_NAME> <SENDER_EMAIL>
Subject: Re: Your AI fraud detection platform
Cc: [redacted: third-party addresses]
Hi <SENDER_NAME>,
Thank you for getting in touch through our website. I'm <TEAM_MEMBER_NAME>, <TEAM_MEMBER_ROLE> of SToFU Systems (<COMPANY_WEBSITE>). You can find me on <PROFESSIONAL_NETWORK> here:
<PROFILE_URL>
Your fraud detection platform sounds like a great project. Helping financial teams spot suspicious transactions and investigate them more effectively is a worthwhile problem to solve, and we'd be very happy to help you bring it to life.
We'd be glad to help with the architecture, development, security, and ongoing maintenance. We'll do everything we can to get the platform launched and keep it running reliably as it grows.
If you plan to seek investment, we can also help prepare the technical side for those conversations, including a working product or demo, clear architecture and documentation, and a practical development roadmap.
Please send over the project overview and technical roadmap you mentioned. It would be helpful to understand what you've already built and what you'd like to tackle first.
I'd be happy to arrange a call to discuss the project and how we could work together. What day and time would suit you? Please include your time zone so we can find a slot that works for both teams.
Thank you again for reaching out, and have a great day!
Best regards,
<TEAM_MEMBER_NAME>
<TEAM_MEMBER_ROLE>
SToFU Systems
<COMPANY_WEBSITE>
Notre réponse demandant les documents. Vue anonymisée du courriel conservé, destinée à la publication.
SHA-256 de l’EML privé non expurgé : 1e5330dd82e02911254722744a3202e9b761c8c1d2950be937cd5d539c1bcad9
3. Le courriel de l’archive mentionnant les branches NDA / conf
Courriel / données identifiantes remplacées
Date: Mon, 19 Oct 2026 09:03:41 +0000
From: <SENDER_EMAIL>
To: <TEAM_EMAIL>
Subject: Re: Your AI fraud detection platform
Hi <TEAM_MEMBER_NAME>,
Thank you for your interest in our AI-powered FinTech fraud detection platform.
I’ve also reviewed your <PROFESSIONAL_NETWORK> profile, and I’m confident that you and your team can make a valuable contribution to our project.
I’m happy to share the project materials for your review.
We’ve prepared the project overview, technical roadmap, and NDA, which provide the key information needed to understand the project, its objectives, and the proposed technical direction.
The platform focuses on AI-driven fraud detection, transaction risk assessment, behavioral analysis, fraud prevention, blockchain-based verification, automated alerts, investigation support, and financial risk analytics.
This is the Link:
<FILE_SHARE_URL>
Please review the project materials and review and sign the NDA in the NDA branch.
The NDA is required because the project materials contain confidential business, technical, architectural, and product information.
So, please send me the signed NDA as soon as possible.
In particular, we would appreciate your initial technical assessment of the proposed system architecture and timeline. The detailed documentation and specifications related to these areas are available in the conf branch.
After your review, we would like to arrange a meeting to discuss your technical observations, recommendations, questions, development approach, and potential partnership opportunities in more detail.
Once you have completed your review, please let me know your preferred meeting date and time and provide the signed NDA.
Please feel free to take the time you need to review the materials thoroughly. I look forward to receiving your feedback and speaking with you about the project.
Kind regards,
<SENDER_NAME>
Le courriel de l’archive mentionnant les branches NDA / conf. Vue anonymisée du courriel conservé, destinée à la publication.
SHA-256 de l’EML privé non expurgé : f7007ed3053d3ba2ef71ea01c74ec0c4aebfd48417f757ecec8d9d7d5884bf33
4. Notre réponse après la découverte du hook
Courriel / données identifiantes remplacées
Date: Mon, 19 Oct 2026 19:37:58 +0200
From: SToFU Systems <TEAM_EMAIL>
To: <SENDER_NAME> <SENDER_EMAIL>
Subject: Re: Your AI fraud detection platform
Hi <SENDER_NAME>,
We reviewed the materials you sent. Unfortunately, we found no application source code or working implementation, only planning documents and an NDA.
Execution of the supplied Git post-checkout hook was disabled during our review. The hook downloads and runs platform-specific files from <DOWNLOAD_DOMAIN>, hides their output, and writes a local marker. Our security policies do not allow the execution of untrusted third-party hooks.
Thank you for your time and for the elaborate attempt to deliver malicious code.
We have traced the technical delivery chain and preserved the archive, hook, download responses, correspondence, and author names and email addresses recorded in the repository. The relevant evidence will be passed to the competent law enforcement authorities in the applicable jurisdictions.
SToFU Systems
Notre réponse après la découverte du hook. Vue anonymisée du courriel conservé, destinée à la publication.
SHA-256 de l’EML privé non expurgé : 31df91adb2eb52be2171836d3e26610328a0a1a1273dbf7d56efe4354bb62e19
- Hook anonymisé, les 101 lignes
- En-tête TAR et début des données du fichier
- Les 24 objets Git
- Blob DOCX avant et après zlib
- Dump de l’arbre NDA
- Les 16 blobs et leurs premiers octets
- Toutes les parties du DOCX
- Limites de gzip et de TAR
- Inspection au niveau des octets dans un format exploitable par machine
- Observations enregistrées des trois points de terminaison
- Sources et hachages des figures
- Provenance de la correspondance
Vue anonymisée du hook complet
Les 101 numéros de ligne du code source ont été conservés. Les informations permettant une identification sont recouvertes de rectangles gris.
Les originaux non expurgés sont conservés à titre privé. Les fichiers de preuve publics utilisent des marqueurs de substitution, et les captures d’écran des rectangles gris opaques. Les hachages étiquetés comme originaux identifient la source privée, et non une copie modifiée destinée à la publication. Les figures sont des captures d’écran de vues locales des preuves, dont le texte permettant une identification a été retiré avant le rendu. Aucun code reçu n’a été exécuté.















