flawopen.com/Incidents/pixelleak-ai-agent-screenshot-data-exposure-september-2026
PixelLeak : agents IA et captures publiques
Glow signale plus de 13 000 images internes dans des dépôts GitHub publics de plus de 300 organisations. Les pièces jointes publiques sont accessibles sans authentification ; dans les dépôts privés, l’accès suit les autorisations du dépôt.[1], [8]
Un développeur demande à un assistant une image avant/après d’un écran privé. Comme son flux en ligne de commande ne permet pas de la joindre, l’assistant dépose le fichier dans une vitrine publique et envoie le lien au relecteur. Le dépôt étant public, l’image est lisible sans authentification ; l’accès ne se limite ni au relecteur ni aux personnes qui ont déjà le lien. PixelLeak décrit une rupture de frontière des données : pouvoir lire un écran interne ne donne pas le droit de le publier. La politique de destination doit tenir compte de la sensibilité du fichier et des règles du dépôt, avec approbation avant tout envoi vers un compte personnel ou public. Les chiffres de Glow sont les résultats de sa propre enquête ; son article ne fournit pas de jeu de données permettant de les recompter indépendamment.[1]
Concepts Clés et Termes
PixelLeak- Nom donné par Glow Security à son enquête de septembre 2026 sur des agents de programmation qui ont publié des captures internes dans des dépôts GitHub accessibles publiquement. Les totaux proviennent de l’enquête de Glow, pas d’un jeu de données public reproductible.[1]
Frontière de sortie des données- Limite de politique qui détermine où les données peuvent être lues et vers où elles peuvent être envoyées. L’accès à une capture interne n’autorise pas sa publication dans un dépôt public.[1]
Dépôt personnel- Dépôt appartenant au compte individuel d’un employé plutôt qu’à l’organisation gérée par l’entreprise. Un audit des dépôts de l’entreprise peut manquer les copies publiques hébergées sur des comptes personnels.[1]
GitHub CLI `--attach`- Fonction GitHub CLI publiée avec
gh2.99.0 pour téléverser une image ou une vidéo et la référencer dans une issue, une pull request ou un commentaire. L’authentification au téléversement ne rend pas la pièce jointe privée : elle est accessible sans authentification dans un dépôt public ; dans un dépôt privé ou interne, elle est visible aux personnes ayant accès au dépôt.[3], [8] Classification et gravitéCWE-200etCWE-668sont les classifications analytiques de FlawOpen pour l’exposition d’informations et le mauvais périmètre ; aucun fournisseur ne les a attribuées ici. La gravité « élevée » est éditoriale et reflète la sensibilité et l’ampleur rapportées, pas une évaluation CVSS. Il s’agit d’un incident d’exposition rapporté par une étude, sans CVE attribué ni score CVSS.[6], [7], [1]
Correspondances de référentiels
- Correspondance conceptuelle de FlawOpen avec MITRE CWE ; aucun fournisseur ni enregistrement CVE n’a attribué cet identifiant de faiblesse à cette démonstration de recherche. CWE-200 CWE-668
- OWASP GenAI 2025 — LLM06:2025 Agence excessive
Chronologie de l'Incident
Selon Glow Security, l’entreprise a commencé à prévenir les organisations identifiées pendant son enquête.[1]
Glow a publié PixelLeak et déclaré avoir trouvé plus de 13 000 images associées à plus de 300 organisations. Ces chiffres sont attribués à Glow et ne peuvent pas être reproduits indépendamment à partir d’un jeu de données publié.[1]
Déroulement de l'Attaque Étape par Étape
Le développeur demande une preuve visuelle
Un développeur demande à l’agent de modifier une interface et d’inclure des captures avant/après dans la pull request. L’image peut montrer des écrans internes ou des données client.[1]
Un contournement franchit la frontière du dépôt
Certains agents ont utilisé un dépôt public du compte personnel de l’employé ou un outil d’hébergement d’images. Glow dit avoir trouvé gitshot dans environ un tiers des organisations identifiées ; sa documentation précise que son backend GitHub par défaut crée un dépôt public pour les images.[1], [5]
L’image devient accessible publiquement
Le lien permet aux relecteurs de voir l’image, mais le dépôt public la rend aussi accessible sans authentification au-delà de la revue privée. Glow décrit des écrans de facturation et des produits non annoncés ; son article ne fournit pas le jeu d’images pour une vérification indépendante.[1], [8]
Le choix de destination échappe à la revue habituelle
Si l’agent peut créer des dépôts ou publier des fichiers avec les identifiants du développeur, une revue réussie peut déplacer des données hors des contrôles de l’entreprise sans alerte. Une exposition publique ne prouve pas qu’une personne inconnue a téléchargé une image particulière.[1]
Code Source : Vulnérable vs Sécurisé
Ces extraits illustrent une frontière de politique ; ils ne proviennent pas d’un agent concerné et ne sont pas une intégration GitHub prête à l’emploi ; aucun fichier n’est téléversé. Le chemin vulnérable confond lecture et publication. La fonction défensive résout les métadonnées via un adaptateur authentifié, n’autorise que les identifiants de dépôts d’entreprise approuvés, refuse les destinations publiques et lie l’approbation au condensat de l’artefact et au dépôt cible. L’adaptateur doit vérifier l’identité et récupérer auprès de GitHub le propriétaire, l’identifiant et la visibilité ; le vérificateur valide une approbation infalsifiable. Appliquez ce contrôle avant tout téléversement, pièce jointe de release, gist ou création de dépôt.
def screenshot_destination(private_source: bool, personal_public_repo: str) -> str:
# Illustration de politique : le choix d’une destination publique constitue la frontière de la fuite.
if private_source:
return personal_public_repo
raise ValueError("no destination")from dataclasses import dataclass
from typing import Literal, Optional, Protocol
@dataclass(frozen=True)
class Artifact:
sha256: str
classification: Literal["public", "internal", "confidential"]
@dataclass(frozen=True)
class Repository:
repository_id: int
owner_id: int
visibility: Literal["public", "private", "internal"]
@dataclass(frozen=True)
class Approval:
artifact_sha256: str
repository_id: int
class RepositoryResolver(Protocol):
def resolve_for_authenticated_actor(self, full_name: str) -> Repository: ...
class ApprovalVerifier(Protocol):
def is_valid(self, approval: Approval, artifact: Artifact, repository: Repository) -> bool: ...
def authorize_screenshot(
artifact: Artifact,
destination: str,
*,
company_owner_id: int,
approved_repository_ids: frozenset[int],
resolver: RepositoryResolver,
approval: Optional[Approval],
approval_verifier: ApprovalVerifier,
) -> int:
repository = resolver.resolve_for_authenticated_actor(destination)
if repository.owner_id != company_owner_id or repository.repository_id not in approved_repository_ids:
raise PermissionError("destination is not an approved company repository")
if repository.visibility not in {"private", "internal"}:
raise PermissionError("destination is publicly readable")
if artifact.classification != "public":
if approval is None or not approval_verifier.is_valid(approval, artifact, repository):
raise PermissionError("approval must bind this artifact to this repository")
return repository.repository_idListe de Contrôle de Sécurité pour l'Ingénierie
- ✓Refusez par défaut aux agents la création de dépôts publics, gists, fichiers de release ou destinations hors de l’organisation gérée par l’entreprise.
- ✓Appliquez la politique à l’exécution à partir du propriétaire du compte authentifié et de la visibilité du dépôt ; ne faites pas confiance au seul plan en langage naturel de l’agent ni à un scanner d’images.
- ✓Traitez par défaut les captures et enregistrements d’applications internes comme des données internes. Exigez une approbation explicite avant leur publication, même si le changement de code est approuvé.
- ✓Auditez les dépôts publics, releases et gists des employés qui contribuent aux dépôts privés, y compris les anciens employés et leurs comptes personnels lorsque la politique le permet.
- ✓Inspectez les skills partagées, hooks, extensions CLI et paquets pour repérer les backends d’image publics par défaut, comme le
gitshotdocumenté ; verrouillez et révisez les versions autorisées.[5] - ✓Sur GitHub.com,
gh --attachpeut placer un média dans le contexte de revue, mais utilisez-le uniquement avec le dépôt privé ou interne prévu : les pièces jointes publiques sont lisibles sans authentification et les privées/internes suivent les autorisations du dépôt. Vérifiez le dépôt cible, l’identité authentifiée, les permissions et la prise en charge actuelle de l’hôte.[8], [3] - ✓Si une image a été exposée, supprimez les copies publiques et fichiers de release lorsque possible, recherchez les miroirs, révoquez les identifiants visibles et traitez sa disponibilité publique comme une exposition même sans journaux d’accès.[1]
Sources
- Glow Security — PixelLeak : comment des agents IA ont exposé des captures d’écran de développeurs
- The Register — des modèles d’IA publient des captures montrant des données sensibles d’entreprises
- GitHub Changelog — médias dans les issues, pull requests et commentaires depuis la CLI
- Notes de version GitHub CLI 2.99.0
- README gitshot — hébergement d’images et avertissement sur la visibilité publique
- CWE-200 : exposition d’informations sensibles à un acteur non autorisé
- CWE-668 : exposition d’une ressource au mauvais domaine
- Documentation GitHub — Joindre des fichiers