Mega Sekurak Hacking Party w Krakowie! 26-27.10.2026 r.
CamoLeak – jak tworząc własny alfabet zdobyć dane z repozytoriów GitHub przez Copilot Chat?
Nie tak dawno temu pisaliśmy o podatności w Microsoft 365 Copilot, zgrabnie nazwanej EchoLeak. Umożliwiała ona – przez wysyłkę spreparowanego maila – wyciek danych z organizacji bez ingerencji użytkownika. Nowa podatność o równie wdzięcznej nazwie – CamoLeak – choć wykryta w podobnym czasie, dopiero niedawno została upubliczniona.
TLDR:
- Podatność CamoLeak pozwalała na pozyskanie przez atakującego danych z prywatnych repozytoriów GitHub przez Copilot Chat.
- Spreparowane pull requests/issues instruowały model, by pobrał graficzną reprezentację danej wartości (np. zmiennej w kodzie). Powodowało to wykonanie żądań do serwera kontrolowanego przez atakującego.
- Wykorzystanie indywidualnych adresów URL dla każdej litery pozwalało obejść ograniczenia GitHub proxy i nagłówków CSP.
- Po zgłoszeniu GitHub zablokował renderowanie jakichkolwiek obrazów w Copilot Chat.
Badacz z Legit Security znalazł sposób na pozyskanie kodu źródłowego z prywatnych repozytoriów GitHub. Całość opierała się na renderowaniu obrazów w odpowiedzi Copilot Chat.
Zaczęło się od próby wpłynięcia na odpowiedź Copilota w treści pull request. Okazuje się, że zmuszenie asystenta do wykonania określonej akcji nie stanowi żadnego problemu:

Jednak taki prompt nie jest w żaden sposób ukryty, co czyni go łatwo wykrywalnym. GitHub umożliwia jednak dodawanie komentarzy, które nie są widoczne w interfejsie ale pozostają dostępne m.in. dla Copilota. Asystent zapytany o dany pull request odniesie się do jego treści wraz z zawartymi w niej komentarzami:

Takie komentarze działają dokładnie tak samo, jak w języku HTML, np.:

Badacz, wykorzystując tę możliwość, zmusił Copilota do zasugerowania użytkownikowi pobrania “zaktualizowanej” wersji narzędzia. Oczywiście można było przekazać w taki sposób dowolne instrukcje.

Istnieje więc łatwa możliwość wpływania na odpowiedź Copilota. Czy można wykorzystać ją do zdobycia danych z prywatnych repozytoriów? Okazuje się, że i to jest możliwe, choć bardziej skomplikowane.
Badacz poinstruował asystenta by – podobnie jak w przypadku ShadowLeak – zakodował treść jednego z plików prywatnego repozytorium użytkownika do postaci base16 i zamieścił w specjalnie przygotowanym adresie URL. Link ten miał zostać wyświetlony jako specjalny kupon Copilot, zachęcając użytkownika do jego kliknięcia. Co ważne, taki atak powiódłby się tylko pod warunkiem otwarcia takiego adresu przez ofiarę.
Ten rodzaj ataku możemy określić jako one-click, bo wymaga podjęcia konkretnej (choć pojedynczej i prostej) akcji przez użytkownika. Można jednak pójść o krok dalej i zrobić z niego zero-click (czyli atak nie wymagający interakcji z użytkownikiem). Badacz zauważył, że co prawda nie można w odpowiedzi Copilota wczytać grafiki bezpośrednio z zewnętrznego serwera (blokują to nagłówki CSP), ale samo użycie takiego zasobu jest możliwe. GitHub korzysta z własnego proxy, wyświetlając zasoby w domenie camo[.]githubusercontent[.]com. Nie ma możliwości odwołania do zewnętrznych domen, o czym jasno informuje dokumentacja.
Niestety, Copilot sam nie przekształci podanego URL na adres w domenie proxy, można jednak uprzednio takie adresy wygenerować i umieścić w prompcie. Nie daje to co prawda możliwości dynamicznego wstawiania parametrów (np. zawierających pozyskane dane), ale i na to jest sposób.
By przesłać dane z prywatnych repozytoriów wystarczyło… stworzyć własny alfabet. A konkretnie:
- Każda litera/znak musiała mieć indywidualny obrazek, a co za tym idzie unikalny adres URL (link) na serwerze atakującego.
- Każdy link (do obrazka przypisanego literze) musiał zostać uprzednio przekonwertowany na adres w domenie proxy (camo) – GitHub umożliwia tworzenie takich linków przez API do renderowania Markdown.
- W treści spreparowanego pull requestu wystarczyło wylistować wszystkie litery wraz z odpowiadającymi im adresami.
- Należało poinstruować model, by przetłumaczył daną treść na obrazki, zamieniając każdą literę na odpowiednią grafikę.
Gdy model wstawiał obrazki w odpowiedzi, każdorazowo proxy GitHuba pobierało je z serwera atakującego. Zastosowano dodatkowo parametr random, który uniemożliwiał zapis odpowiedzi w cache. Dzięki temu w logach serwera, do którego – przez proxy – były wykonywane żądania, widać było kolejno każdą pobieraną literę:

Takie działanie pozwalało potencjalnemu atakującemu na pozyskanie dowolnych (dynamicznie wstawionych) danych poprzez zapytania wykonywane do uruchomionego w tym celu serwera.
Możliwe było wysłanie w taki sposób m.in. treści zgłoszeń (issues) w prywatnym repozytorium ofiary (lub udostępnionego ofierze), a także fragmentów kodu. Przykładowy prompt badacza pozwalał przeszukać repozytorium pod kątem klucza do usług AWS:

Po zgłoszeniu podatności, GitHub zablokował w ramach Copilota wczytywanie zasobów także z domeny proxy camo[.]githubusercontent[.]com, co uniemożliwiło wykonywanie tego typu ataków. Jest to kolejny przykład, jak niebezpieczne może okazać się udzielanie szerokich dostępów narzędziom AI.
W przypadku CamoLeak niezbędne było użycie Copilota przez ofiarę, mającą z poziomu swojego konta dostęp do repozytoriów będących w zainteresowaniu atakującego. Niestety pokazuje to, że – podobnie jak w przypadku podatności ShadowLeak – zbyt szerokie dostępy i możliwości udzielane agentom AI to też liczne wektory ataku.
Warto więc ograniczyć używanie tego typu narzędzi do sytuacji, gdy całkowicie kontrolujemy dane wejściowe (np. praca tylko na własnym kodzie). Jeśli chcemy korzystać informacji dostarczanych przez zewnętrznych użytkowników (m.in. issues, pull requests), warto robić to w izolowanym środowisku (np. na osobnym koncie z dostępem tylko do publicznych repozytoriów).
Źródła:
- www.legitsecurity.com (tutaj także wideo z PoC tej podatności)
- docs.github.com
~Tymoteusz Jóźwiak