genai
SECURITY LAB
IncidentsData exfiltration

CamoLeak: Silent Private-Repo Theft via GitHub Copilot Chat

Critical severityOctober 2025LLM01: Prompt InjectionLLM02: Sensitive Information DisclosureLLM10: Improper Output Handling
Status: CVE-2025-59145 (CVSS 9.6); reported via HackerOne by Legit Security, fixed by GitHub in Aug 2025 (Camo/CSP hardening)
On this page

Invisible text in a pull request turned a developer's own AI assistant into a channel for stealing their private code.

WhenOctober 2025
TargetGitHub Copilot Chat
ResearcherOmer Mayraz (Legit Security)
TechniqueIndirect prompt injection + Camo/CSP-bypass exfiltration
CVECVE-2025-59145 — CVSS 9.6 (Critical)
Attack flow
  1. 1An attacker hides instructions in an invisible markdown comment in a PR or issue
  2. 2The victim's GitHub Copilot Chat ingests the content and follows the hidden instructions
  3. 3Copilot reads private-repo data and leaks it via a dictionary of GitHub-signed Camo image URLs

What happened

In 2025, Legit Security's Omer Mayraz disclosed CamoLeak (CVE-2025-59145, CVSS 9.6): a critical flaw that let an attacker exfiltrate a victim's private source code through their own GitHub Copilot Chat. Instructions hidden in an invisible markdown comment in a pull request were read by Copilot as an indirect prompt injection. GitHub fixed it in August 2025.

How the attack worked

The hidden instructions told Copilot to search the victim's private repositories (for example, for AWS keys) and encode what it found. To defeat GitHub's content-security policy — which routes images through a 'Camo' proxy precisely to block image-based exfiltration — the researcher pre-computed a dictionary of validly-signed Camo URLs, one per character. Copilot spelled out the stolen data character by character as the browser fetched those trusted image URLs.

The clever partThe exfiltration channel was the very control meant to prevent it: legitimately-signed Camo image URLs the CSP already trusted.

Root cause

Untrusted repository content (a PR comment) was allowed to instruct the assistant, and the assistant's output could trigger outbound image fetches that carried data — so the CSP's own allowlist became an exfiltration path.

What a test would have caught

An indirect-injection test that plants hidden markup in ingestible content and checks whether the assistant will read privileged data or emit encoded outbound URLs would have surfaced both halves before shipping.

How to prevent it

  • Strip and normalise invisible markup before content reaches the model.
  • Treat repo content as untrusted; don't let it act as instructions.
  • Deny data-bearing egress — even signed image URLs — from model-influenced output.

Feel it yourselfThe replay lab recreates the exfiltration class CamoLeak abused — get an assistant to leak its context through a rendered image URL.

FAQ

How does hidden text in a PR reach Copilot?

GitHub markdown supports comments that render invisibly to humans but are still read by the model. When Copilot Chat ingests the PR/issue, those hidden instructions become an indirect prompt injection the user never sees.

Why is bypassing the Camo proxy the clever part?

GitHub's content-security policy normally blocks image-based exfiltration by routing images through its 'Camo' proxy. The researcher pre-generated a dictionary of validly-signed Camo URLs, one per character, so the stolen data could be spelled out through image fetches the CSP still trusted.

How do you defend against it?

Treat any repo content the assistant reads as untrusted, strip/normalise invisible markup before it reaches the model, and don't let model-influenced output mint outbound requests (even 'trusted' image URLs) that can encode data.

Replay this attack
Exfiltrate an assistant's context by getting it to render an image whose URL carries the data — the channel CamoLeak abused.
Open the live lab
Runs as a live, sandboxed lab. Sign-in required — this replay is a Pro lab. Recreates the attack class, not this exact branded bot.