Vie privée dans le navigateur · Recherche indépendante ·
Comment LinkedIn détecte les extensions
Rétro-ingénierie d’un signal navigateur, des requêtes en échec à une chaîne de télémétrie conditionnelle.
Le client capturé était conçu pour tester 4 934 extensions et signaler les résultats positifs. Les deux détecteurs ont renvoyé des tableaux vides lors du test consigné. J’ai reconstitué le chemin de signalement, sans observer la transmission d’un identifiant d’extension.
J’ai retracé le JavaScript de production avec DevTools, vérifié les résultats des détecteurs à l’exécution et construit une analyse Python reproductible du catalogue exporté.
Dossier complet sur GitHub- 4 934
- 2
- 0
01
Les requêtes à l’origine de l’enquête
En naviguant sur LinkedIn, j’ai remarqué des échecs répétés de requêtes chrome-extension://invalid/ dans Chrome DevTools. Remonter à l’initiateur d’une requête m’a d’abord conduit à une fonction enveloppant window.fetch. L’examen de ses arguments et de ses appelants a révélé un mécanisme précis : la page testait des identifiants d’extension et des chemins de ressources connus.
J’ai utilisé des points d’arrêt, des journaux de résultats et l’inspection des prototypes pour relier les requêtes au code de détection, puis exporté son catalogue de cibles. Les 175 observations conservées correspondent toutes à cet export. Le total de 4 934 provient du catalogue et des boucles du code.

02
Deux façons de chercher une extension
Les deux fonctions obtiennent leurs signaux de manière différente. Aucune ne fournit un inventaire complet des extensions installées.
Détection active : demander une ressource connue
Le détecteur actif construit des URL chrome-extension:// à partir des identifiants et chemins du catalogue. Sa branche parallèle utilise Promise.allSettled et retient les résultats de fetch résolus avec une valeur non undefined, sans vérifier Response.ok ni lire le corps de la réponse. Une autre branche procède séquentiellement, avec un délai facultatif. Le timeout de requestIdleCallback concerne la planification, pas le délai réseau de chaque fetch.
Détection passive : lire les références dans la page
Le détecteur passif parcourt les nœuds de texte et les attributs des éléments à la recherche de références chrome-extension://. Il extrait le premier identifiant apparent après ce préfixe dans chaque chaîne. L’implémentation capturée ne valide pas son format, ne supprime pas les doublons et ne vérifie pas qui a inséré la référence. Elle ne parcourt pas non plus explicitement les racines shadow DOM ni les documents des iframes. Une correspondance constitue un signal, pas une preuve d’installation.
03
Le résultat qui limite la conclusion
Les résultats actifs positifs alimentent AedEvent ; les résultats passifs alimentent SpectroscopyEvent. Les deux points d’émission vérifient que le résultat est un tableau contenant au moins un élément avant de transmettre browserExtensionIds. Dans les exécutions consignées, les deux tableaux étaient vides : aucune de ces conditions ne déclenchait donc son événement d’extension.
Un résultat vide ne prouve pas l’absence d’extensions installées. Chrome restreint l’accès aux ressources par défaut ; les règles d’origine, les changements de ressources et les identifiants dynamiques peuvent empêcher une détection fondée sur un identifiant fixe. Le parcours passif présente ses propres limites de couverture. Aucun contrôle positif n’a été conservé : cette étude ne mesure donc pas la précision des détecteurs.
DETECTED: [] COUNT: 0
SPECTROSCOPY: [] COUNT: 0
04
Suivre le chemin de signalement
À partir de fireTrackingPayload, j’ai suivi le client de télémétrie partagé à travers la création des enveloppes, la sélection des routes, les files d’attente, la préparation des requêtes et la fonction finale de fetch. Les recherches à l’exécution associaient les deux noms d’événement à normal-priority. Des indicateurs d’activation distincts peuvent encore sélectionner l’ancien chemin, le nouveau, ou les deux ; identifier une destination ne prouve pas qu’un événement l’a empruntée.
Le gestionnaire inspecté avait une taille de lot de 30 et un délai de regroupement de 10 000 ms. La fonction de transport essayait fetch avec keepalive activé, puis réessayait sans cette option en cas de rejet. Malgré le nom beaconFunc plus haut dans la chaîne, ce chemin aboutissait à fetch ; ce nom ne démontrait pas un appel à navigator.sendBeacon.
À l’étape finale du transport, j’ai inspecté une requête réelle contenant LixTreatmentsEvent, avec une enveloppe JSON et une configuration gzip. Elle fournissait un exemple concret du transport partagé, utilisé pour un autre événement.
- 01Résultat du détecteur
- 02Condition non vide
- 03Client de télémétrie
- 04Transport partagé
05
Mesurer le catalogue
L’export contient un chemin de ressource pour chacun des 4 934 identifiants uniques, soit 2 487 chemins distincts. Il ne contient ni nom de produit, ni version, ni nombre d’installations, ni raison d’inclusion. J’ai analysé ce JSON hors ligne avec Python, en séparant les mesures directes des indices suggérés par les noms de fichiers.
Les fichiers PNG représentent près de la moitié des cibles. Le chemin exact le plus fréquent, icons/icon16.png, apparaît 407 fois. Ces chemins génériques ne permettent pas d’identifier fiablement la fonction d’une extension, et une cible JavaScript ne signifie pas que le détecteur en a exécuté le code.
Le dossier de recherche associe dix identifiants choisis intentionnellement à des fiches publiques de produits ; les 4 924 autres restent non identifiés. Ce petit échantillon n’est pas représentatif. Je n’ai pas converti les correspondances de noms de fichiers en estimations du nombre de cibles remplissant une fonction donnée.
| Ressource | Cibles | Part |
|---|---|---|
| PNG | 2 308 | 46,78 % |
| JavaScript (.js) | 854 | 17,31 % |
| HTML (.html) | 808 | 16,38 % |
| CSS | 507 | 10,28 % |
| Autres suffixes | 457 | 9,26 % |
06
Enjeux de vie privée et explication de LinkedIn
La question de vie privée que je retiens concerne ce qu’un résultat positif pourrait révéler sur les logiciels choisis par une personne. La fonction d’une extension peut suggérer des intérêts ou des habitudes de travail, sans établir de caractéristiques personnelles ni la raison de son installation. Il s’agit d’une implication possible du mécanisme, pas d’un usage des données observé. Cela invite à examiner le périmètre de collecte, la conservation et les accès.
L’objectif déclaré par LinkedIn
Dans une déclaration publiée par BleepingComputer le 3 avril 2026, LinkedIn explique détecter des extensions pour lutter contre le scraping et les violations de ses conditions, améliorer ses défenses techniques et examiner les récupérations inhabituellement importantes de données de membres. L’entreprise affirme ne pas utiliser ces signaux pour déduire des informations sensibles sur les membres. Cette explication n’a pas été vérifiée par mon investigation dans le navigateur.
Le contexte de sa politique de confidentialité
La politique de confidentialité de LinkedIn mentionne les modules complémentaires du navigateur parmi les informations sur l’appareil (§1.5), ainsi que la sécurité, la prévention de la fraude et les enquêtes parmi les usages des données (§2.9). Ces indications donnent du contexte, sans préciser la composition du catalogue capturé ni la conservation et le traitement de ces événements particuliers.
07
Ce que je retiens de cette investigation
La difficulté consistait à préserver le sens de chaque étape : une cible n’est pas une détection, une détection n’est pas un événement émis, et une route configurée ne prouve pas une livraison. Remonter au-delà de la première fonction intermédiaire, examiner les méthodes héritées et relier le code aux valeurs consignées à l’exécution m’a permis de comprendre le système sans exagérer le résultat.
Cette investigation porte sur le code client de ma propre session connectée, documentée le 12 septembre 2026. J’ai mené le travail dans DevTools avec l’aide d’une IA, également utilisée pour le suivi du code, l’analyse du catalogue et la rédaction. J’ai vérifié l’analyse à partir des éléments conservés. L’article d’Antoine Vastel chez Castle, paru en janvier 2026, décrit des travaux antérieurs sur ce mécanisme ; je ne revendique pas sa découverte.
Le dossier ne comprend ni HAR complet, ni résultat positif contrôlé, ni accès au backend. Il ne permet pas d’établir la conservation, le profilage, le partage ou la raison du ciblage d’une extension précise. Ces questions restent à adresser à l’opérateur. Le travail apporte une analyse reproductible du catalogue et une description traçable du signalement conditionnel côté client, y compris le résultat négatif.
08
Éléments de preuve et sources
Une sélection des fichiers de l’investigation est disponible ci-dessous. Le catalogue liste des cibles possibles, pas mes extensions installées. Les 175 observations y correspondent exactement. Les données de session personnelles et le contenu de console sans rapport sont exclus.
Dossier complet sur GitHub- Catalogue de cibles exporté
- Analyse du catalogue
- Cibles observées dans la console
- Code capturé des détecteurs
- Capture originale de la console