Brotli CVE-2026-111497: Node.js, Bun және Python жаңарту
CVE-2026-111497 - Google-дың Brotli декодеріндегі жадыны бүлдіру қатесі, яғни Content-Encoding: br деректерін ашатын C тіліндегі код. Арнайы дайындалған сығылған деректер буфердің шегінен тыс жазады, бұл бағдарламаны құлатуы, жадыдағы деректерді ағызуы немесе шабуылдаушының кодын орындауы мүмкін. Node.js, Bun, Python-ның Brotli және brotlicffi пакеттері мен Envoy әрқайсысы осы декодердің өз көшірмесін бірге алып жүреді, сондықтан әрқайсысын бөлек жаңарту керек. Бұл нұсқаулық қолданба шын мәнінде қашан осал болатынын, серверді бір командамен қалай тексеруге болатынын және бірде-бір контейнерді жіберіп алмай түзетуді қалай енгізуге болатынын көрсетеді.
Қаншалықты қауіпті
- Google оны CVSS 4.0 бойынша 9.2 (critical) деп бағалайды, Node.js - high, Red Hat - 8.1.
- Imperva зерттеушілері Linux ARM64-тегі түзетілмеген Node.js 24.22.0 нұсқасында өз кодын орындады - fetch арқылы алынған жауап арқылы да, Express-тегі сұрау денесі арқылы да. Эксплойт жария етілмеген.
- CISA-ның 23 қазандағы бағалауында нақты шабуылдарда пайдалану тіркелмеген, сенімді жария proof of concept жоқ.
- Осалдық екі бағытта да жұмыс істейді: сығылған кіріс деректерін ашатын серверге клиент шабуыл жасай алады, ал сығылған жауаптарды ашатын клиентке - сервер.
Түзету Brotli бастапқы кодына 27 ақпанда қосылды, бірақ 21 қазанға дейін ешбір Brotli релизі оны қамтымады, сондықтан түзетілген рантаймдардың бәрі бір аптада шықты.
Сіз осалсыз ба?
Тек басқа біреу басқаратын Brotli деректерін декодтайтын код қауіпте:
- Node.js және Bun -
Content-Encoding: brарқылы жіберілген жауапты оқитын кірістірілгенfetch(), сенімсіз деректергеnode:zlibарқылы Brotli шақырулары және Brotli жүктемелерін ашатын сұрау денесінің парсерлері (Express 5, body-parser 2). Қарапайым Node.js HTTP-сервері сұрау денесін өзі декодтамайды. - Python - Brotli немесе brotlicffi пакетінің орнатылғаны жеткілікті: сонда requests, urllib3, httpx және aiohttp Brotli жауаптарын өздері декодтайды, тіпті сіздің кодыңыз Brotli-ды ешқашан импорттамаса да.
- Envoy және Istio - тек Brotli декомпрессия сүзгісі бапталған болса ғана.
Үшінші тарап API-ларына, вебхуктерге, төлем провайдерлеріне жүгінетін немесе беттерді парсинг жасайтын кез келген қызмет сіз басқармайтын серверлерге fetch() орындайды. Accept-Encoding ішінен br алып тастау түзету емес: сервер бәрібір Brotli жібере алады.
| БҚ | Осал нұсқалар | Түзетілген нұсқа |
|---|---|---|
| Node.js | түзетуге дейінгі 22.x, 24.x, 26.x; 20.x және ескірек (қолдау тоқтатылған) | 22.23.4, 24.22.1, 26.12.1 |
| Bun | 1.4.3 және ертерек | 1.4.4 |
| Python Brotli | 1.2.0 және ертерек | 1.2.1 |
| Python brotlicffi | 1.2.0.x және ертерек | 1.2.1.0 |
| Google Brotli (C кітапханасы) | 1.0.3 - 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
| Envoy | 1.39.2, 1.38.5, 1.37.7, 1.36.11 | 1.40.0, 1.39.3, 1.38.6, 1.37.8, 1.36.12 |
| Istio | 1.31.0 - 1.31.1, 1.30.0 - 1.30.5, 1.29.0 - 1.29.8 | 1.31.2, 1.30.6, 1.29.9 |
Серверді бір командамен тексеру
Бұл POSIX shell-скрипті машинадағы (немесе контейнер ішіндегі) Bun, Node.js және Python-ды тексеріп, қайсысы түзетуден ескі екенін көрсетеді. Оны brotli-check.sh деп сақтаңыз:
#!/bin/sh
# CVE-2026-111497 (Brotli decoder): which runtimes on this host are older than the fixes?
ver_lt() { [ "$1" = "$2" ] && return 1; [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]; }
if command -v bun >/dev/null 2>&1; then
v=$(bun --version)
if ver_lt "$v" 1.4.4; then echo "bun $v: VULNERABLE, upgrade to 1.4.4+"; else echo "bun $v: fixed"; fi
fi
if command -v node >/dev/null 2>&1; then
v=$(node -p "process.versions.bun ? '' : process.versions.node")
if [ -z "$v" ]; then echo "node: this is Bun's node shim, see the bun line"; else major=${v%%.*}
case $major in
22) fix=22.23.4 ;; 24) fix=24.22.1 ;; 26) fix=26.12.1 ;;
*) fix= ;;
esac
if [ -z "$fix" ]; then echo "node $v: no fixed release for this line, move to 22, 24 or 26"
elif ver_lt "$v" "$fix"; then echo "node $v: VULNERABLE, upgrade to $fix+"
else echo "node $v: fixed"; fi
fi
fi
for py in python3 python; do
command -v $py >/dev/null 2>&1 || continue
$py - <<'PY'
from importlib import metadata
for pkg, fix in (("Brotli", "1.2.1"), ("brotlicffi", "1.2.1.0")):
try:
v = metadata.version(pkg)
except metadata.PackageNotFoundError:
print(f"python {pkg}: not installed")
continue
a = [int(x) for x in v.split(".") if x.isdigit()]
b = [int(x) for x in fix.split(".")]
print(f"python {pkg} {v}: {'VULNERABLE, upgrade to ' + fix + '+' if a < b else 'fixed'}")
PY
break
done
sh brotli-check.sh
docker exec my-app sh -s < brotli-check.sh # the same check inside a running container
Нәтиже 2026-10-24 күні тексерілді (әзірлеушінің ноутбугі, содан кейін ресми Docker образдары):
bun 1.4.1: VULNERABLE, upgrade to 1.4.4+
node 26.6.0: VULNERABLE, upgrade to 26.12.1+
python Brotli: not installed
python brotlicffi: not installed
bun 1.4.4: fixed
node: this is Bun's node shim, see the bun line
node 22.23.4: fixed
node 16.20.2: no fixed release for this line, move to 22, 24 or 26
python Brotli 1.1.0: VULNERABLE, upgrade to 1.2.1+
python brotlicffi: not installed
Скриптті тек хостта емес, әр контейнерде іске қосыңыз: хосттағы Node.js образ ішіне салынған Node.js туралы ештеңе айтпайды.
Түзетуді қалай енгізу керек
- Әр көшірмені табыңыз. Көбіне образдар назардан тыс қалады. Не іске қосылғанын тізіп шығыңыз:
docker ps --format '{{.Image}}', содан кейін Dockerfile ішіндегіFROMжолдары.node:22немесеoven/bun:alpineсияқты тег тек pull жасағанда ғана алға жылжиды;oven/bun:1.4.1-slimсияқты бекітілген тег ешқашан жылжымайды. - Рантаймды жаңартыңыз. Бекітілген тегтерді көтеріңіз (
oven/bun:1.4.4-slim,node:22.23.4-alpine), хосттардаbun upgradeорындап, Node.js пакеттерін жаңартыңыз, ал Python ортасында -pip install -U "Brotli>=1.2.1"(немесеbrotlicffi>=1.2.1.0). Егер Python қолданбасына Brotli қажет болмаса,pip uninstall Brotli brotlicffiда бұл жолды жабады: HTTP-клиенттер gzip пен deflate-қа ауысады. - Қайта құрып, ауыстырыңыз.
docker compose build --pull && docker compose up -d. Іске қосылған процесс қайта іске қосылғанға дейін ескі декодерді ұстап тұрады, сондықтан хосттардағы қызметтерді де қайта іске қосыңыз. - Тексеріңіз. Тексеру скриптін әр контейнерде қайта іске қосыңыз (
docker exec <name> bun --version- жылдам нұсқасы). Тәуелділіктерді жаңартқаннан кейін--frozen-lockfileбар lockfile қайта құруды бұзуы мүмкін: жаңартылған lockfile-дыpackage.json-мен бірге коммиттеңіз. - Әлі жаңарта алмайсыз ба? Денені бірдеңе декодтамай тұрып, прокси деңгейінде
Content-Encoding: brбар сұрауларды қабылдамаңыз және сенімсіз хосттардан деректер жүктеуден аулақ болыңыз. Vercel атап өткендей, файрвол ережелері сіздің өз кодыңыз басқа серверлерден алатын жауаптарды қамтымайды - тек жаңарту көмектеседі.
VM-дағы Node.js стегі үшін Node.js үшін бұлттық сервер, Python үшін Python және Flask үшін бұлттық сервер, ал таза қайта құрылатын образдар үшін Docker Swarm үшін бұлттық сервер мақаласын қараңыз.
Біз не істедік
Түзетулер шыққаннан кейін бірнеше күн ішінде Bun-да жұмыс істейтін DCXV-дің әр қызметін 1.4.4 нұсқасына көшірдік: бекітілген базалық образдар түзетілген тегтерге ауыстырылды, ал барлық образдар жаңа pull арқылы қайта құрылды. Біздің Node.js компоненттеріміз Brotli денелерін декодтамайды, ал проксилерімізде Brotli декомпрессиясы жоқ. Клиент серверлерін олардың иелері басқарады: егер сіз DCXV бұлттық серверінде Node.js, Bun немесе Python іске қоссаңыз, жоғарыдағы тексеруді бүгін орындаңыз немесе бізден басқарылатын сервер әкімшілігі туралы сұраңыз.
Дереккөздер (2026-10-24 күні тексерілді): Node.js-тің 2026 жылғы қазандағы қауіпсіздік релиздері (22.23.4, 24.22.1, 26.12.1), Bun 1.4.4 релизі, CISA-ның 2026 жылғы 23 қазандағы бағалауы және Imperva зерттеуі.
