ApostropheCMS uploadfs z backendem Azure ujawnia token SAS w publicznych adresach URL załączników
Podsumowanie
Gdy uploadfs jest skonfigurowane z backendem Azure oraz opcją sas: true (obsługiwana konfiguracja wprowadzona w uploadfs 1.25.0), createContainer() tworzy BlobServiceClient na podstawie adresu URL zawierającego pełny ciąg zapytania SAS, a klienci pochodni w Azure SDK v12 dziedziczą ten ciąg zapytania. W rezultacie getUrl() zwraca bazowy adres URL zawierający pełną sygnaturę SAS konta/kontenera (?sv=...&sig=...), a attachment.url() w Apostrophe dołącza go jako prefiks do każdego publicznego linku do załącznika — ujawniając poświadczenie SAS na poziomie kontenera (zazwyczaj sp=rwdlac, czyli pełny dostęp do odczytu, zapisu, usuwania i listowania) każdemu odwiedzającemu witrynę, w tym użytkownikom anonimowym. Każdy, kto widzi adres URL załącznika, może odczytywać, nadpisywać, usuwać oraz listować każdy obiekt blob w kontenerze przez cały okres ważności tokenu SAS. Towarzyszący błąd funkcjonalny (ścieżka blobu jest dołączana za ciągiem zapytania, co generuje uszkodzone adresy URL) wskazuje, że ta ścieżka kodu nigdy nie była testowana całościowo. Domyślny tryb klucza współdzielonego (shared-key) oraz backendy inne niż Azure nie są dotknięte tym problemem.
Zweryfikowano na commicie 5a3746aaed49761e171c2cbfe793267c959829fd (uploadfs 1.27.0 w monorepozytorium apostrophe).
Szczegóły
Przyczyna źródłowa: adres URL klienta zawierający poświadczenia jest ponownie wykorzystywany jako publiczny bazowy adres URL. Przebieg łańcucha:
- Klient z osadzonymi poświadczeniami: azure.js#L123-L125 —
new BlobServiceClient("https://<account>.blob.core.windows.net?<SAS query string>"), gdziecluster.keyjest pełnym ciągiem SAS zawierającymsig - Miejsce wycieku: azure.js#L513-L520 —
getUrl()przyjmujegetContainerClient(...).getBlobClient('').urljakobaseUrl; klienci pochodni w SDK v12 dziedziczą ciąg zapytania SAS, więcbaseUrlzawiera już?sv=...&sig=... - Ujawnienie publiczne: attachment/index.js#L694 —
attachment.url()=uploadfs.getUrl() + pathdla każdego renderowanego linku do załącznika; attachment/index.js#L1503 —getBrowserData()przekazuje równieżuploadsUrldo każdej zalogowanej sesji edytora - Towarzyszący błąd: ścieżka blobu jest dołączana po ciągu zapytania (
/container/?sv=...&sig=XXX/attachments/id-name), przez co te adresy URL są również uszkodzone — co dowodzi, że ścieżka kodu 1.25.0 nie była testowana
Powierzchnia ataku: każda publiczna strona renderująca adresy URL załączników (obrazy, linki do pobierania), a także uploadsUrl dostarczane do sesji edytora. Wyciek jest pasywny i bezwarunkowy — od ofiary nie wymaga się żadnych działań poza serwowaniem strony. Poświadczenie rozprzestrzenia się dodatkowo przez kod źródłowy HTML, logi, nagłówki Referer oraz logi dostępowe CDN i serwerów proxy.
Sugerowane środki zaradcze:
- Usunięcie ciągu zapytania przed tworzeniem publicznych adresów URL:
const u = new URL(blob.svc.getContainerClient(...).getBlobClient('').url); u.search = '';(lub ręczne złożenieaccountUrl + '/' + container) oraz dołączanie ścieżki blobu do ścieżki (pathname), a nie za ciągiem zapytania. - Udokumentowanie, że tryb SAS musi stosować zasadę najmniejszych uprawnień (tylko do odczytu, najlepiej
sr=bdla pojedynczego blobu) oraz preferowanie generowania krótkotrwałych, podpisanych adresów URL tylko do odczytu dla pojedynczego blobu za pośrednictwemgenerateBlobSASQueryParameterszamiast osadzania tokenu SAS poziomu usługi w stałych publicznych adresach URL.
PoC
Pełny PoC zamieszczono w pierwszym komentarzu poniżej (poc.js + README; tryb offline, konto Azure nie jest wymagane). Odtwarza on dokładnie dwa kroki biblioteki przy użyciu zadeklarowanej zależności @azure/storage-blob@12:
npm install @azure/storage-blob@12 && node poc.js- Skrypt konstruuje
new BlobServiceClient("https://myaccount.blob.core.windows.net?sv=...&sig=FAKESIGNATURE")dokładnie tak jakcreateContainer(), następnie ewaluuje logikęgetUrl()(getContainerClient('uploads-container').getBlobClient('').url) i potwierdza, że wynikowy bazowy adres URL nadal zawiera parametrsig. - Zaobserwowany wynik (kod wyjścia 0):
baseUrl: https://myaccount.blob.core.windows.net/uploads-container/?sv=2021-06-08&ss=b&srt=co&sp=rwdlac&se=2099-01-01&sig=FAKESIGNATURE
attachment URL as served to visitors: https://myaccount.blob.core.windows.net/uploads-container/?sv=2021-06-08&ss=b&srt=co&sp=rwdlac&se=2099-01-01&sig=FAKESIGNATURE/attachments/abc123-photo.jpg
Wygenerowany adres URL ujawnia token (sv…sig) oraz wykazuje nieprawidłowe umiejscowienie ścieżki. Weryfikacja z attachment/index.js potwierdza, że ten adres URL trafia na strony publiczne w postaci niezmienionej.
Wpływ
- Czym jest problem: niewystarczająco chronione poświadczenia (CWE-522) prowadzące do ujawnienia informacji (CWE-200). Token SAS na poziomie kontenera — zazwyczaj posiadający uprawnienia
sp=rwdlac(odczyt/zapis/usuwanie/listowanie/ACL) — zostaje ujawniony każdemu odwiedzającemu witrynę, w tym użytkownikom anonimowym, i pozostaje ważny przez cały okres życia tokenu (często lata). Posiadacze tokenu mogą odczytywać, nadpisywać, usuwać oraz przeglądać wszystkie załączniki w kontenerze; biblioteka nie stosuje żadnych ograniczeń. - Kogo dotyczy: witryn Apostrophe korzystających z uploadfs z backendem Azure i opcją
sas: true(wprowadzoną w 1.25.0; obecną do wersji 1.27.0). Domyślny tryb klucza współdzielonego oraz inne backendy nie są dotknięte problemem. Gdy token SAS został utworzony wyłącznie z uprawnieniem do odczytu, wpływ ogranicza się do nieuwierzytelnionego odczytu i pobierania wszystkich załączników.
Zgłoszone przez Kimi Security Team (bug-report@moonshot.ai).
Co trzeba zrobić
Zaktualizuj pakiet uploadfs do wersji 1.28.0 lub nowszej.
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Paczka npm | uploadfs | >= 1.25.0, < 1.28.0 | 1.28.0 |
Odnośniki
- https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-hhph-8536-gfq5
- https://github.com/apostrophecms/apostrophe/commit/9500b8b0e1d630d5e07fbb5fd2c25ed0943845ce
- https://github.com/apostrophecms/apostrophe/commit/f84fd41cbf6c22eb8d0008fc9c25df1f7130b350
- https://github.com/apostrophecms/apostrophe
- https://github.com/apostrophecms/apostrophe/releases/tag/uploadfs@1.28.0
- Wektor CVSS
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L- Słabość (CWE)
CWE-200, CWE-522- Platforma
- npm
- Paczka
uploadfs- Ujawniono
- 20.10.2026
- Aktualizacja
- 20.10.2026 21:30
Źródła i licencje · Redakcja lub tłumaczenie: DockRay. Zachowano prawa źródeł i obowiązujące licencje.
OSV / GitHub Advisory Database - GHSA-hhph-8536-gfq5 - CC BY 4.0
Historia podatności: uploadfs
Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
To jedyna znana podatność tej paczki.
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.