Node.js güvenlik açığı: Node2Shell yaması ve Node.js sürümünü kontrol etme (WordPress)

Node2Shell, yaması 21 Ekim 2026'da yayımlanan Node.js güvenlik açığı CVE-2026-111497'nin takma adıdır; resmî başlığı Google'ın Brotli kod çözücüsündeki sınır dışı yazma kusurunu anlatır. Özel olarak hazırlanmış Brotli sıkıştırılmış verisinin açıldığı anda uzaktan kod yürütmeye yol açabildiği için önce sunucunuzdaki Node.js, Bun ve libbrotli sürümlerini kontrol edip yamalı sürümlere yükseltmeniz gerekir.
WordPress 7.1.3 çalışan Nginx + Apache yapılı bir sunucuda Brotli kod çözücüsünü kullanan paketleri ve WordPress uzak isteklerinin libbrotli'den geçtiği yolu kontrol ettim.
1️⃣ Node.js güvenlik açığı Node2Shell: Kusurun çalışma şekli ve etki alanı
Node2Shell adı, güvenlik şirketi Imperva'nın araştırma ekibinin 22 Ekim'deki araştırma yazısında verdiği bir takma addır. nodejs.org duyurusunun başlığı [Brotli decoder out-of-bounds write permits remote code execution] şeklindedir. Kusur, Node.js'in içinde gelen Google Brotli kod çözücüsünün kaynak kodunda (c/dec/decode.c) bulunduğu için uygulama kodunu düzelterek engellenemez.
NVD kaydına göre Google Brotli 1.0.3–1.2.0 kod çözücüsü, özel olarak hazırlanmış bir sıkıştırılmış akışı açarken arabelleğin sonunu aşarak yazar ve bitişikteki kod çözücü durum belleğini bozar. Oturum açmamış uzak bir saldırgan bu kusurla sunucu belleğinin içeriğini okuyabilir, hizmeti durdurabilir ve rastgele kod çalıştırabilir.
İki ciddiyet derecelendirmesi vardır. nodejs.org duyurusu High seviyesini verdi; CVE'yi yayımlayan Google ise CVSS 4.0'a göre 9,2 (Critical) puan verdi. NVD 23 Ekim itibarıyla kendi analizini bitirmediği için henüz NVD puanı yoktur. Zayıflık türleri, denetlenmeyen dönüş değeri (CWE-252) ve sınır dışı yazmadır (CWE-787).
nodejs.org güvenlik duyurusuna göre desteklenen Node.js 22.x, 24.x ve 26.x serilerinin tümü etkileniyor ve yamalı sürümler 22.23.4, 24.22.1 ve 26.12.1'dir. Aynı duyuru, desteği sona ermiş serilerin her güvenlik duyurusunda her zaman etkilenmiş sayıldığını belirtiyor.
Aynı kod çözücüyü kullanan programların hepsi, Node.js dışında da etkileniyor. Google 21 Ekim'de aynı CVE'yi düzelten Brotli kütüphanesinin üç sürümünü yayımladı: 1.0.10, 1.1.1 ve 1.2.1. Bun, 22 Ekim'deki 1.4.4 duyurusunun güvenlik düzeltmeleri listesine Brotli'yi ekledi; depodaki bir issue da bu sürümün brotli'yi güncelleyen düzeltmeyi içerdiğini belirtiyor.
| hedef | Etkilenen sürümler | Düzeltilmiş sürüm | Kaynak |
|---|---|---|---|
| Node.js | Desteklenen tüm seriler 22.x · 24.x · 26.x · desteği sona ermiş seriler | 22.23.4 · 24.22.1 · 26.12.1 | nodejs.org güvenlik duyurusu (2026-10-21) |
| Google'ın Brotli kütüphanesi | 1.0.3 ~ 1.2.0 | 1.0.10 · 1.1.1 · 1.2.1 | NVD kaydı · google/brotli sürümleri (2026-10-21) |
| Bun | 1.4.4 duyurusunun güvenlik düzeltmeleri listesinde Brotli | 1.4.4 | Bun duyurusu (2026-10-22) |
| Dağıtımın libbrotli paketi | Brotli 1.0.3–1.2.0 temel alınarak hazırlanan paketler | Dağıtımın güvenlik duyurusunda verilen sürüm (2026-10-23 itibarıyla henüz yok) | Her dağıtımın güvenlik takip sayfası |
Node.js'in kendisi aldığı Brotli verisini kendiliğinden açmaz. Hosting şirketi Vercel'in güvenlik duyurusuna göre açığa çıkan noktalar, bir uygulamanın veya kütüphanenin dışarıdan gelen sıkıştırılmış veriyi açtığı yerlerdir. Yerleşik fetch()'in br yanıtı aldığı ve Express 5 ile body-parser 2'nin br istek gövdesini açtığı durumlar buna örnektir; yalnızca veri alan varsayılan HTTP sunucusu açma işlemi yapmaz.
23 Ekim itibarıyla gerçek bir istismar doğrulanmadı. CISA'nın bilinen istismar edilmiş güvenlik açıkları kataloğunda (KEV, 21 Ekim sürümü) bu CVE yer almıyor. CISA'nın CVE kaydında verdiği istismar aşaması 23 Ekim'de [kavram kanıtı (PoC) yayımlandı] olarak değişti.
Kod çözücünün nerede bulunduğu yapılacak işi belirler. Node.js'in resmî ikili dosyaları kod çözücüyü çalıştırılabilir dosyanın içinde taşır; Debian'ın nodejs paketi gibi sistemin libbrotli'sini kullanan derlemeler de vardır. Linux dağıtımları aynı kaynak kodu libbrotli paketi olarak kurar ve curl gibi programlar bunu ortak kullanır.
2️⃣ WordPress ve PHP siteleri de etkileniyor: Uzak isteklerin yanıtları libbrotli ile açtığı yol
Node.js kurulu olmayan bir WordPress sunucusunda da aynı kod çözücü libbrotli paketi olarak bulunur. 23 Ekim itibarıyla WordPress, curl ve PHP tarafında bu CVE'yi ele alan resmî bir açıklama yoktur; curl'ün resmî güvenlik açığı listesinde de bu CVE yer almaz. Bu yüzden bu bölüm yalnızca yapıyı çekirdek kodu, curl belgeleri ve test sunucusundaki ölçümlerle doğrular.
Ölçüm yapılan Nginx + Apache yapılı sunucuda kod çözücü kütüphanesini (libbrotlidec) gerektiren beş paket vardı ve bunlardan WordPress'e bağlanan libcurl'dür.
rpm -q --whatrequires 'libbrotlidec.so.1()(64bit)' | sed 's/-[0-9].*//'freetype
brotli-devel
libjxl
libcurl
libsouplibcurl'ün libbrotli'ye ihtiyaç duymasının nedeni sıkıştırılmış HTTP yanıtlarını açmaktır. curl'ün resmî belgelerine göre brotli kütüphanesiyle birlikte derlenen libcurl, Content-Encoding değeri br olan yanıtları otomatik olarak açar. Bu libcurl'ü PHP'nin curl eklentisi doğrudan çağırır.
ldd /usr/lib64/libcurl.so.4 | grep brotli libbrotlidec.so.1 => /lib64/libbrotlidec.so.1 (0x00007f32803ed000)
libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1 (0x00007f327f858000)php -i | grep BROTLIBROTLI => YesWordPress'in kullandığı libcurl sürümü, yönetim ekranında [Araçlar › Site sağlığı] altındaki [Bilgiler] sekmesinde [Sunucu] bölümünü açtığınızda [cURL sürümü] satırında görünür. brotli desteğinin olup olmadığı bu satırda yazmadığı için yukarıdaki gibi sunucu komutlarıyla kontrol edersiniz.
Görseldeki [cURL sürümü] satırı, libcurl sürümünü birlikte derlendiği SSL kütüphanesiyle gösterir. curl belgelerine göre br 7.57.0'dan beri desteklenen bir yöntemdir; bu değer daha düşükse br yanıtları açılamaz. Eşit veya daha yüksekse derlemede brotli olup olmadığını sunucu komutlarıyla kontrol edersiniz.
WordPress çekirdeğindeki Requests kütüphanesi, dış bir adrese istek gönderirken curl tanıtıcısının [CURLOPT_ENCODING] değerini boş dize olarak ayarlar. curl belgelerine göre boş dize, o libcurl'ün desteklediği tüm sıkıştırma yöntemlerini kabul etmek anlamına gelir. Bu yüzden karşı sunucu br ile sıkıştırılmış bir yanıt gönderirse WordPress sunucusundaki libbrotli onu açar.
grep -n CURLOPT_ENCODING wp-includes/Requests/src/Transport/Curl.php110: curl_setopt($this->handle, CURLOPT_ENCODING, '');
212: curl_setopt($this->handle, CURLOPT_ENCODING, 'none');110. satır tüm istekler için varsayılan değerdir; 212. satır ise açılamayan bir isteğin sıkıştırmasız yeniden gönderildiği durumda çalışır. Dışarıdan doğrudan tetiklemenin yolu yoktur; önce çekirdek ve eklenti güncelleme kontrolleri, oEmbed veya RSS beslemeleri gibi WordPress'in yanıt aldığı karşı sunucunun ele geçirilmesi gerekir.
Akış dışarıdan gelen br ile sıkıştırılmış veriyle başlar. Kusur, Node.js'in fetch()'i, Express 5, Bun'ın fetch()'i veya WordPress'in libcurl'ünün çağırdığı libbrotli bu veriyi açarken tetiklenir. Sonuç sunucuda kod yürütmeye varır. Yamalı sürümler bu akışı engellediği için yapılacak iş kod çözücüyü yamalı sürümle değiştirmektir.
Apache'nin mod_brotli modülü yalnızca yanıtları sıkıştıran kodlayıcı kütüphanesini (libbrotlienc) bağladığı için bu modülle sıkıştırmayı açan bir yapılandırma kod çözücü kusurunun yolunda bulunmaz.
ldd /usr/lib64/httpd/modules/mod_brotli.so | grep brotli libbrotlienc.so.1 => /lib64/libbrotlienc.so.1 (0x00007f34b4b79000)
libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1 (0x00007f34b4a79000)3️⃣ Node.js sürümünü kontrol etme: Sunucuda Node.js, Bun ve libbrotli olup olmadığı ve sürümleri
İşe sunucuda nelerin kurulu olduğunu çıkararak başlayın. Node.js için sürümü [node -v] ile görün; değer, serisine göre 22.23.4, 24.22.1 veya 26.12.1'den düşükse etkileniyor demektir.
| Ortamınız | Kontrol komutu | Düzeltilen yer |
|---|---|---|
| nodejs.org yükleyicisi · nvm · resmî Docker imajı | [node -v] | Node.js'in kendisi (22.23.4 · 24.22.1 · 26.12.1) |
| Dağıtımın nodejs paketi · ldd çıktısında libbrotli satırı var | [ldd $(command -v node)] | libbrotli paketi |
| Dağıtımın nodejs paketi · ldd sonucu 0 | [ldd $(command -v node)] | nodejs paketi (dağıtımın güvenlik duyurusundan sonra) |
| Paylaşımlı hostingde Node.js Selector (CloudLinux alt-nodejs) | Sağlayıcı duyurusu · paketin release numarası | Sağlayıcının dağıttığı paket + uygulamayı yeniden başlatma |
| Bun | [bun --version] | Bun 1.4.4 veya üzeri |
| Node.js yok (yalnızca WordPress) | [ldd] ile libcurl kontrolü | libbrotli paketi + php-fpm yeniden başlatma · o zamana kadar geçici önlem |
| Yönetilen hosting | Sağlayıcı duyurusu · destek talebi | Sağlayıcının yükselttiği paketler |
PC'de (Windows veya macOS) nodejs.org'daki yamalı sürüm yükleyicisiyle yeniden kurun; nvm'de sürümü [nvm ls] ile gördükten sonra [nvm install 24] gibi seri numarasıyla yeniden kurun. Resmî Docker node imajının 22, 24 ve 26 etiketleri 22 Ekim'de yamalı sürümlerle yeniden oluşturulduğu için imajı yeniden çekip derleyin ve dağıtın. Vercel duyurusu, kendi derlediğiniz kapsayıcı imajlarını, CI çalıştırma ortamlarını ve yerel geliştirme ortamlarını da yamalı sürümlere yükseltmenizi öneriyor.
dnf module akışıyla Node.js'i kurduğunuz sunucuda [node -v] o akışın serisindeki sürümü gösterir; seri aynı olsa bile son haneler yamalı sürüme ulaşmıyorsa yükseltmeniz gerekir.
node -vv24.xx.xNode.js'in sistemin libbrotli'sini mi yoksa yerleşik kod çözücüyü mü kullandığını [ldd] ile kontrol edersiniz. Çıktıda libbrotlidec satırı varsa derleme ortak kütüphaneyi kullanıyordur; aşağıdaki gibi 0 ise kod çözücü yerleşiktir ve sorun ancak Node.js'in kendisini yükseltince düzelir.
ldd $(command -v node) | grep -c brotli0Bun'da sürümü [bun --version] ile kontrol edin ve 1.4.4'ten düşükse yükseltin.
RPM tabanlı sistemlerde libbrotli paketinin sürümünü [rpm -q libbrotli] ile görürsünüz. Paket sürüm numaralarını dağıtım verdiği için bunları doğrudan Google'ın sürüm numaralarıyla değil, dağıtımın güvenlik duyurusunun bu CVE numarası için yayımladığı sürümle karşılaştırın.
rpm -q libbrotlilibbrotli-1.0.x-x.el9_x.x86_64Dağıtımın duyuru yayımlayıp yayımlamadığını [dnf updateinfo info --cve CVE-2026-111497] ile kontrol edersiniz. Çıktı boşsa o depoda bu CVE için henüz duyuru yoktur.
dnf updateinfo info --cve CVE-2026-111497Sürüm numarasını aynı bırakıp yalnızca düzeltmeyi aktaran paketler değişiklik günlüğünde CVE numarasını bırakır. Bu yüzden [rpm -q --changelog libbrotli | grep CVE-2026-111497] ile kontrol edin; bir satır çıkarsa paket yamalıdır.
rpm -q --changelog libbrotli | grep CVE-2026-11149723 Ekim itibarıyla Debian, Ubuntu, Red Hat ve AlmaLinux'un libbrotli paketlerinde bu CVE için henüz yamalı sürüm yok. Alpine'de yalnızca nodejs paketi için yamalı sürüm çıktı; kaynak her dağıtımın güvenlik takip sayfasıdır. Bu yüzden şimdilik sıra, dağıtımın güvenlik duyurusunu takip edip çıktığında yükseltmektir.
Debian ve Ubuntu'da paket adı libbrotli1'dir ve aynı maddeleri yönetilen bir hosting sağlayıcısındaki Debian 12 test sunucusunda kontrol ettim. Bu sunucuda da libcurl libbrotlidec'i bağlıyordu ve PHP'nin curl eklentisi brotli'yi destekliyordu. Değişiklik günlüğünü [zcat /usr/share/doc/libbrotli1/changelog.Debian.gz | grep CVE-2026-111497] ile görürsünüz.
dpkg -l libbrotli1 | tail -1ii libbrotli1:amd64 1.1.0-2+0~20240305.8+debian12~1.gbp62df71 amd64 library implementing brotli encoder and decoder (shared libraries)ldd /usr/lib/x86_64-linux-gnu/libcurl.so.4 | grep brotli libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007fa2baac6000)
libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007fa2b9cb9000)4️⃣ Node.js güncelleme: Yamalı sürüme yükseltip yeniden kontrol edin
Yönetilen ve paylaşımlı hostingde sunucu paketlerini sağlayıcı yükselttiği için Node.js ve libbrotli'ye yamanın uygulanıp uygulanmadığını sağlayıcının duyurularından veya destek ekibinden öğrenin. Sunucuyu kendiniz yönetiyorsanız Node.js'i nodejs.org duyurusundaki yamalı sürüme, Bun'ı da [bun upgrade] ile 1.4.4 veya üzerine yükseltin.
Dağıtımın modül akışıyla kurulan Node.js, o depoya yamalı sürüm geldikten sonra [dnf upgrade nodejs] biçiminde yükseltilir. nodejs.org'dan doğrudan indirip kurduğunuz sunucularda aynı yerdeki yamalı sürümle değiştirin. Desteği sona ermiş serilere yamalı sürüm çıkmadığı için desteklenen 22, 24 veya 26 serisine geçin.
Paylaşımlı hostingdeki Node.js Selector (CloudLinux alt-nodejs) brotli'nin ayrı bir kopyasını taşıdığı için sistemin libbrotli'sini yükseltmek sorunu düzeltmez. CloudLinux duyurusuna göre yeni ikili dosya, sağlayıcının dağıttığı pakete geçildikten ve uygulama yeniden başlatıldıktan sonra çalışır. Aynı duyuru, desteği sona ermiş sürümlerde [node --version] değerinin değişmediğini, bu yüzden paketin release numarasıyla kontrol edildiğini belirtti.
libbrotli paketinde dağıtımın güvenlik duyurusu çıkınca paketi yükseltin ve kütüphaneyi belleğe yüklemiş süreçleri yeniden başlatın; ancak o zaman yeni kütüphaneye geçilir. Ortak kütüphaneler süreç başlarken okunduğu için WordPress sunucusunda php-fpm'i yeniden başlatmak da aynı adımın parçasıdır.
Yükselttikten sonra [node -v] çıktısının yamalı sürüm veya üzeri olduğunu ve [rpm -q libbrotli] çıktısının dağıtım duyurusundaki sürüm olduğunu kontrol edin. Değişiklik günlüğüne CVE numarasının girip girmediğini [rpm -q --changelog libbrotli | grep CVE-2026-111497] ile kontrol edin. php-fpm'i yeniden başlattıysanız hizmet durumunu ve sitenin yanıtını da kontrol edin.
systemctl is-active php-fpmactivecurl -s -o /dev/null -w '%{http_code}\n' 'https://example.com/?r=1'2005️⃣ Yama öncesi geçici önlem: WordPress uzak isteklerinde br açmayı kapatma
Red Hat'in CVE sayfası, güvenilmeyen kaynaklardan gelen br sıkıştırmasını kabul etmeyecek veya otomatik olarak açmayacak şekilde uygulamaların ayarlanmasını öneriyor.
Yamalı paketler çıkmadan önce de WordPress tarafındaki yolu hemen kapatabilirsiniz. WordPress, her uzak istekte curl tanıtıcısını aktaran [http_api_curl] kancasını sağlar. Orada [CURLOPT_ENCODING] değerini null yaparsanız libcurl'ün otomatik açma özelliği kapanır.
Aşağıdaki dosyayı [wp-content/mu-plugins/] klasörüne koyarsanız tüm uzak isteklere uygulanır; dosya adı bir örnektir. Geri almak için bu dosyayı silmeniz yeterlidir.
<?php
// no-brotli-decode.php — WordPress uzak isteklerde libcurl Otomatik açma Kapalı(libbrotli yama sürüm çıkacak kadar)
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'http_api_curl', function ( $handle ) {
curl_setopt( $handle, CURLOPT_ENCODING, null );
}, 99 );[CURLOPT_ENCODING] değerini [gzip, deflate] ile sınırlarsanız br'nin devre dışı kalacağı düşünülebilir. Bu değer yalnızca isteğin Accept-Encoding başlığından br'yi çıkarır; karşı sunucu br ile yanıt verirse libcurl aldığı yanıtı yine açar. Test sitesinde aynı değerle httpbin.org/brotli alındığında Content-Encoding değeri br olan yanıt olduğu gibi açılıp okundu.
curl belgelerine göre otomatik açmayı kapatan tek değer null'dur; null olduğunda Accept-Encoding başlığı gönderilmez ve alınan gövde de açılmaz. gzip ve deflate yanıtlarını WordPress'in Requests kütüphanesi kendisi açar ve okunabilir kalırlar; yalnızca br yanıtları açılmadan kalır.
Bu kanca, WordPress'in Requests'in curl'ü çalıştırmadan hemen önce çağırdığı [curl.before_send] noktasına bağladığı kancadır. Curl.php'nin 174. satırında çağrılıp 205. satırında çalıştırıldığı için çekirdeğin 110. satırda koyduğu boş dize değeri arada üzerine yazılır.
Uygulanıp uygulanmadığını aşağıdaki test dosyasıyla kontrol edin. httpbin.org, aldığı istek başlıklarını geri döndüren ve br ile gzip ile sıkıştırılmış yanıtlar da veren bir test adresi olduğundan WordPress'in ne gönderdiği ve neyi açtığı tek seferde görülür.
<?php
// br-check.php — WordPress uzak istek hangi sıkıştırma gönderir açıp açmadığı Kontrol et(httpbin.org test Adres)
$h = json_decode( wp_remote_retrieve_body( wp_remote_get( 'https://httpbin.org/headers' ) ), true );
echo 'Accept-Encoding: ', isset( $h['headers']['Accept-Encoding'] ) ? $h['headers']['Accept-Encoding'] : '(none)', PHP_EOL;
foreach ( array( 'brotli', 'gzip' ) as $p ) {
$r = wp_remote_get( 'https://httpbin.org/' . $p );
$readable = strpos( wp_remote_retrieve_body( $r ), ': true' ) !== false;
echo $p, ': Content-Encoding=', wp_remote_retrieve_header( $r, 'content-encoding' ), ' / ', strlen( wp_remote_retrieve_body( $r ) ), ' bytes / ', ( $readable ? 'readable' : 'not decoded' ), PHP_EOL;
}Dosyayı eklemeden önce Accept-Encoding içinde br vardır ve br yanıtı açılıp okunur.
wp eval-file br-check.phpAccept-Encoding: deflate, gzip, br
brotli: Content-Encoding=br / 316 bytes / readable
gzip: Content-Encoding=gzip / 317 bytes / readableDosyayı ekledikten sonra Accept-Encoding başlığı kaybolur, br yanıtı açılmadan kalır ve gzip yanıtı okunmaya devam eder.
wp eval-file br-check.phpAccept-Encoding: (none)
brotli: Content-Encoding=br / 199 bytes / not decoded
gzip: Content-Encoding=gzip / 272 bytes / readableDağıtımın yamalı libbrotli paketini yükseltip php-fpm'i yeniden başlattıktan sonra bu dosyayı silerek eski haline döndürün.
🔢 SSS & önerilen içerikler
Güvenlik
OpenSSH güvenlik açığı CVE-2024-6387
OpenSSH kusurunu geçici olarak engelledikten sonra yamayı uygulayıp kontrol ettiğim süreç.
Güvenlik
WP güvenliği: wp-admin güvenliği
Giriş adresini değiştirip giriş denemelerini sınırlayarak ve XML-RPC'yi engelleyerek yönetim ekranını koruyan ayarlar.
Sunucu
Alma Linux güncellemesi: 9.4 → 9.8
AlmaLinux 9.4'ü 9.8'e yükselttiğim iş adımları ve kontrol maddeleri.
ℹ️ Satış ortaklığı bildirimi
Bu sitenin içeriklerinde satış ortaklığı bağlantıları bulunur. Bir ziyaretçi bu bağlantılar üzerinden ürün veya hizmet satın alırsa bu site satıcıdan komisyon alır. Bu süreçte alıcının ödediği tutar (kampanya indirimlerinde tutar düşer↓) artmaz. Yayımlanan fiyat, indirim ve stok bilgileri yazının yazıldığı zamana aittir ve gerçek durumdan farklı olabilir; bu yüzden satın almadan önce son bilgiyi satıcıdan kontrol etmenizi rica ederiz. Ürünler kendi ölçütlerimize göre seçilir ve değerlendirilir; komisyon alınıp alınmaması tanıtım sırasını veya değerlendirme içeriğini etkilemez.