Use-after-free trong bộ mã hóa QPACK của nginx HTTP/3
10 phút đọc19/06/2026
Trung NguyenHacker. Builder. Educator. On a mission to make the internet safer.
Về tác giả

Trung NguyenHacker. Builder. Educator. On a mission to make the internet safer. Hacker. Builder. Educator. On a mission to make the internet safer.
Cập nhật thông tin mới nhấtNhận các thông tin mới nhất về mối đe dọa, báo cáo an ninh mạng từ CyStack về hòm thư điện tử của bạn
"<!DOCTYPE html>\n<html>\n <head>\n <title>Sign in ・ Cloudflare Access</title>\n \n <meta charset=\"utf-8\" />\n <meta name=\"robots\" content=\"noindex\" />\n <meta name=\"viewport\" content=\"initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 62 50'%3E %3Cstyle%3E path %7B fill: url(%23gradient-light); %7D @media (prefers-color-scheme: dark) %7B path %7B fill: url(%23gradient-dark); %7D %7D %3C/style%3E %3Cdefs%3E %3ClinearGradient id='gradient-light' x1='30.7' y1='0' x2='30.7' y2='49.8' gradientUnits='userSpaceOnUse'%3E %3Cstop stop-color='%23332CB3'/%3E %3Cstop offset='1' stop-color='%23456FDD'/%3E %3C/linearGradient%3E %3ClinearGradient id='gradient-dark' x1='30.7' y1='0' x2='30.7' y2='49.8' gradientUnits='userSpaceOnUse'%3E %3Cstop stop-color='%23FFFFFF'/%3E %3Cstop offset='1' stop-color='%23E0E0E0'/%3E %3C/linearGradient%3E %3C/defs%3E %3Cpath d='M21.3 15.6h-7.8C17.2 6.4 26.1 0 36.6 0c13.7 0 24.9 11.1 24.9 24.9 0 13.7-11.1 24.9-24.9 24.9-10.4 0-19.4-6.4-23.1-15.6h7.8c3.1 5.1 8.8 8.6 15.3 8.6 9.9 0 17.9-8 17.9-17.9 0-9.9-8-17.9-17.9-17.9-6.5 0-12.1 3.4-15.3 8.6zm-12 14l-3.1-3.1h36.7c1.4 0 2.1 1.7 1.1 2.7l-6.2 6.2-2.2-2.2 3.6-3.6H9.3zm23-12.9l2.2-2.2 6.2 6.2c1 1 .3 2.7-1.1 2.7H3.1L0 20.2h35.9l-3.6-3.5z'/%3E %3C/svg%3E \" />\n <article id=\"data\"\n data-auto-redirect-to-identity=\"false\"\n data-auto-redirect-url=\"\"\n data-message=\"\">\n </article>\n <style>@charset \"UTF-8\";:root{color-scheme:light;--color-kumo-canvas:oklch(98.75% 0 0);--color-kumo-elevated:oklch(98% 0 0);--color-kumo-recessed:oklch(96% 0 0);--color-kumo-base:#fff;--color-kumo-tint:oklch(97% 0 0);--color-kumo-control:#fff;--color-kumo-line:oklch(14.5% 0 0 / 0.1);--color-kumo-hairline:oklch(93.5% 0 0);--color-kumo-fill:oklch(92.2% 0 0);--color-kumo-brand:oklch(57.72% 0.2324 260);--color-kumo-danger:oklch(63.7% 0.237 25.331);--color-kumo-success:oklch(59.6% 0.145 163.225);--color-kumo-focus:oklch(15% 0 0);--color-interstitial-deny:oklch(62% 0.19 25.331);--color-interstitial-approve:oklch(62.7% 0.19 149.214);--text-color-kumo-default:oklch(21% 0.006 285.885);--text-color-kumo-subtle:oklch(55.6% 0 0);--text-color-kumo-placeholder:oklch(70.8% 0 0);--text-color-kumo-link:oklch(42.4% 0.199 265.638);--text-color-kumo-info:oklch(42.4% 0.199 265.638);--text-color-kumo-warning:oklch(47.6% 0.114 61.907);--text-color-kumo-danger:oklch(50.5% 0.213 27.518);--text-color-kumo-success:oklch(43.2% 0.095 166.913);--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--spacing:4px;--content-width:460px;--content-width-wide:540px;--content-width-xl:680px;--page-bg-override:initial}*,::after,::before{-webkit-box-sizing:border-box;box-sizing:border-box}body,html{margin:0;padding:0;min-height:100vh;min-height:100dvh}html{text-rendering:optimizeLegibility;word-wrap:break-word}.Content,body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}body,html{background:var(--page-bg-override, #003d7b)}body{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#4f566b;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding:calc(var(--spacing)*8) calc(var(--spacing)*2);text-align:center}button{font-family:inherit}.Content{width:100%;max-width:var(--content-width);margin:0 auto;gap:calc(var(--spacing)*5)}.Content-is-wide{max-width:var(--content-width-wide)}.Content-is-xl{max-width:var(--content-width-xl)}.base_AccessLogo{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.Content::after{content:\"\";display:block;height:41px;-ms-flex-negative:0;flex-shrink:0}.base_AccessLogo svg{width:280px;max-width:100%;height:auto;display:block}.AuthBox{width:100%;background:var(--color-kumo-base);border:1px solid var(--color-kumo-hairline);border-radius:var(--radius-lg);overflow:hidden;text-align:left}.AuthBox-body{padding:calc(var(--spacing)*8);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;gap:calc(var(--spacing)*4)}.AuthBox-body-is-centered,.OrgAvatarLink{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.AuthBox-body-is-centered{text-align:center}.OrgAvatarLink{display:-webkit-box;display:-ms-flexbox;display:flex;gap:calc(var(--spacing)*3);text-decoration:none;color:inherit}.OrgAvatarLink-logo{-ms-flex-negative:0;flex-shrink:0;height:36px}.OrgAvatarLink-logo:has(img[src=\"\"]){display:none}.OrgAvatarLink-logo img{display:block;height:36px;width:auto;border-radius:var(--radius-sm)}.OrgAvatarLink-title{font-size:14px;line-height:20px;font-weight:500;color:var(--text-color-kumo-subtle)}.AuthBox-App{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;gap:var(--spacing)}.Card-title{margin:0;font-size:24px;line-height:32px;font-weight:600;color:var(--text-color-kumo-default)}.AuthBox-body p,.Card-subtitle,.Result p{margin:0;font-size:14px;line-height:20px;color:var(--text-color-kumo-default)}.Header-text{background:var(--color-kumo-tint);border:1px solid var(--color-kumo-hairline);border-radius:var(--radius-md);padding:calc(var(--spacing)*3) calc(var(--spacing)*4);font-size:13px;line-height:18px;color:var(--text-color-kumo-default)}.AuthBox-App>.Header-text{margin-top:calc(var(--spacing)*3)}.AuthBox-text,.InfoRow h3{font-size:14px;line-height:20px;font-weight:500;color:var(--text-color-kumo-default);margin:0 0 2px}.Result{gap:var(--spacing)}.Result p{color:var(--text-color-kumo-subtle)}.InfoList,.InfoRow,.Result{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.InfoList{gap:calc(var(--spacing)*5)}.InfoRow{gap:var(--spacing)}.InfoRow h3{margin:0;font-size:13px;line-height:18px;font-weight:600}.InfoRow p,.StandardInput{font-size:14px;color:var(--text-color-kumo-default)}.InfoRow p{margin:0;line-height:20px}.StandardInput{-moz-appearance:none;appearance:none;-webkit-appearance:none;display:block;width:100%;height:44px;padding:0 calc(var(--spacing)*3);font:inherit;background:var(--color-kumo-control);border:1px solid var(--color-kumo-line);border-radius:var(--radius-lg);-webkit-transition:background-color 120ms ease;transition:background-color 120ms ease}.StandardInput::-webkit-input-placeholder{color:var(--text-color-kumo-placeholder)}.StandardInput::-moz-placeholder{color:var(--text-color-kumo-placeholder)}.StandardInput:-ms-input-placeholder{color:var(--text-color-kumo-placeholder)}.StandardInput::-ms-input-placeholder{color:var(--text-color-kumo-placeholder)}.StandardInput::placeholder{color:var(--text-color-kumo-placeholder)}.AuthFormLogin,.AuthFormLogin-row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.AuthFormLogin{gap:calc(var(--spacing)*3);margin:0}.AuthFormLogin-row{gap:var(--spacing)}.AuthFormLogin-row label,.Button{font-size:14px;line-height:20px;font-weight:500}.AuthFormLogin-row label{color:var(--text-color-kumo-default);margin-bottom:2px}.AuthFormLogin input[hidden]{display:none}.Button{-moz-appearance:none;appearance:none;-webkit-appearance:none;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;gap:calc(var(--spacing)*2);height:44px;padding:0 calc(var(--spacing)*4);font-family:inherit;border-radius:var(--radius-lg);border:1px solid transparent;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.05);box-shadow:0 1px 2px 0 rgba(0,0,0,.05);cursor:pointer;text-decoration:none;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:background-color 120ms ease,border-color 120ms ease,color 120ms ease,-webkit-box-shadow 120ms ease,-webkit-transform 60ms ease;transition:background-color 120ms ease,border-color 120ms ease,color 120ms ease,box-shadow 120ms ease,transform 60ms ease;transition:background-color 120ms ease,border-color 120ms ease,color 120ms ease,box-shadow 120ms ease,transform 60ms ease,-webkit-box-shadow 120ms ease,-webkit-transform 60ms ease}.Button:focus-visible{outline-offset:2px}.Button:active{-webkit-transform:translateY(.5px);-ms-transform:translateY(.5px);transform:translateY(.5px)}.Button:disabled{opacity:.5;cursor:not-allowed;-webkit-transform:none;-ms-transform:none;transform:none}.Button-is-block{width:100%}.Button-is-destructive,.Button-is-interstitial-approve,.Button-is-interstitial-deny,.Button-is-primary{background:-webkit-gradient(linear,left top,left bottom,from(color-mix(in oklch,var(--button-emphasis-color),white 15%)),to(var(--button-emphasis-color)));background:linear-gradient(to bottom,color-mix(in oklch,var(--button-emphasis-color),white 15%),var(--button-emphasis-color));color:#fff;border-color:color-mix(in oklch,var(--button-emphasis-color),black 10%)}.Button-is-destructive:hover:not(:disabled),.Button-is-interstitial-approve:hover:not(:disabled),.Button-is-interstitial-deny:hover:not(:disabled),.Button-is-primary:hover:not(:disabled){background:-webkit-gradient(linear,left top,left bottom,from(color-mix(in oklch,var(--button-emphasis-color),white 30%)),to(var(--button-emphasis-color)));background:linear-gradient(to bottom,color-mix(in oklch,var(--button-emphasis-color),white 30%),var(--button-emphasis-color))}.Button-is-primary{--button-emphasis-color:var(--color-kumo-brand)}.Button-is-destructive{--button-emphasis-color:var(--color-kumo-danger)}.Button-is-interstitial-deny{--button-emphasis-color:var(--color-interstitial-deny)}.Button-is-interstitial-approve{--button-emphasis-color:var(--color-interstitial-approve)}.Button-is-secondary{background:var(--color-kumo-base);color:var(--text-color-kumo-default);border-color:var(--color-kumo-hairline)}.Button-is-secondary:hover:not(:disabled){background:var(--color-kumo-tint)}.Button-is-secondary:active:not(:disabled){background:var(--color-kumo-fill)}.Button-is-auth{background:var(--color-kumo-base);color:var(--text-color-kumo-default);border-color:var(--color-kumo-hairline);-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;padding:0 calc(var(--spacing)*4);gap:calc(var(--spacing)*3)}.Button-is-auth:hover:not(:disabled){background:var(--color-kumo-tint)}.Button-is-auth:active:not(:disabled){background:var(--color-kumo-fill)}.Button-is-small{height:26px;padding:0 calc(var(--spacing)*2);gap:calc(var(--spacing)*1);font-size:12px;line-height:16px;border-radius:var(--radius-md)}.Button-auth-service-icon{-ms-flex-negative:0;flex-shrink:0;width:20px;height:20px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.Button-auth-service-icon img,.Button-auth-service-icon svg{width:20px;height:20px;display:block}.AuthBoxRow--name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500}.CardActions{display:-webkit-box;display:-ms-flexbox;display:flex;gap:calc(var(--spacing)*3);margin:0}.CardActions .Button{-webkit-box-flex:1;-ms-flex:1;flex:1}.Footer-text{margin:calc(var(--spacing)*4) calc(var(--spacing)*-8) calc(var(--spacing)*-8);padding:calc(var(--spacing)*4) calc(var(--spacing)*8);background:var(--color-kumo-elevated);border-top:1px solid var(--color-kumo-hairline);font-size:12px;line-height:18px;color:var(--text-color-kumo-subtle);text-align:left}.Footer-text span{white-space:pre-line}.Message,.resend-confirmation{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;gap:calc(var(--spacing)*3);padding:calc(var(--spacing)*3) calc(var(--spacing)*4);border:1px solid;border-radius:var(--radius-lg);font-size:14px;line-height:20px;text-align:left}.Message{display:-webkit-box;display:-ms-flexbox;display:flex}.Message svg{-ms-flex-negative:0;flex-shrink:0;width:16px;height:16px;margin-top:2px}.Message svg path{fill:currentColor}.Message-is-info{background:#f4f9ff;border-color:#5b9bd5;color:var(--text-color-kumo-info)}.Message-is-warning{background:#fffef6;border-color:#e6c84a;color:var(--text-color-kumo-warning)}.Message-is-error{background:#fffbfb;border-color:#fd959b;color:var(--text-color-kumo-danger)}.Message-is-success,.resend-confirmation{background:#f8fefb;border-color:#5cb87a;color:var(--text-color-kumo-success)}@media (max-width:480px){body{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;padding:calc(var(--spacing)*8) calc(var(--spacing)*4) calc(var(--spacing)*4)}.base_AccessLogo svg{width:220px}.Content::after{display:none}.AuthBox-body{padding:calc(var(--spacing)*5)}.Card-title{font-size:20px}.Footer-text{margin:calc(var(--spacing)*4) calc(var(--spacing)*-5) calc(var(--spacing)*-5);padding:calc(var(--spacing)*3) calc(var(--spacing)*5)}}@media (prefers-reduced-motion:reduce){*,::after,::before{-webkit-transition-duration:.01ms!important;transition-duration:.01ms!important;-webkit-animation-duration:.01ms!important;animation-duration:.01ms!important}}.AuthBox-AuthGroup,.AuthBox-Normal{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.AuthBox-Normal{display:-webkit-box;display:-ms-flexbox;display:flex;gap:calc(var(--spacing)*4)}.AuthBox-AuthGroup{gap:var(--spacing)}.AuthBox-AuthGroup,.AuthServiceLogin,.kumo-divider{display:-webkit-box;display:-ms-flexbox;display:flex}.AuthServiceLogin{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;gap:calc(var(--spacing)*2)}.kumo-divider{-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:calc(var(--spacing)*3);color:var(--text-color-kumo-subtle)}.kumo-divider::after,.kumo-divider::before{content:\"\";-webkit-box-flex:1;-ms-flex:1;flex:1;height:1px;background:var(--color-kumo-hairline)}.kumo-divider__label{font-size:13px;line-height:18px;font-weight:500}.AuthBox-RequestCode{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;gap:calc(var(--spacing)*2)}</style>\n\n <!-- URL polyfill for IE11 -->\n <script>!function(e){\"use strict\";function t(t){return!!t&&(\"Symbol\"in e&&\"iterator\"in e.Symbol&&\"function\"==typeof t[Symbol.iterator]||!!Array.isArray(t))}function n(e){return\"from\"in Array?Array.from(e):Array.prototype.slice.call(e)}!function(){var r,a=e.URL;try{if(a){if(\"searchParams\"in(r=new e.URL(\"http://example.com\")))return;\"href\"in r||(r=void 0)}}catch(e){}function i(e){var t=\"\",n=!0;return e.forEach(function(e){var r=encodeURIComponent(e.name),a=encodeURIComponent(e.value);n||(t+=\"&\"),t+=r+\"=\"+a,n=!1}),t.replace(/%20/g,\"+\")}function o(e,t){var n=e.split(\"&\");t&&-1===n[0].indexOf(\"=\")&&(n[0]=\"=\"+n[0]);var r=[];n.forEach(function(e){if(0!==e.length){var t=e.indexOf(\"=\");if(-1!==t)var n=e.substring(0,t),a=e.substring(t+1);else n=e,a=\"\";n=n.replace(/\\+/g,\" \"),a=a.replace(/\\+/g,\" \"),r.push({name:n,value:a})}});var a=[];return r.forEach(function(e){a.push({name:decodeURIComponent(e.name),value:decodeURIComponent(e.value)})}),a}function u(e){var r=this;this._list=[],null==e||(e instanceof u?this._list=o(String(e)):\"object\"==typeof e&&t(e)?n(e).forEach(function(e){if(!t(e))throw TypeError();var a=n(e);if(2!==a.length)throw TypeError();r._list.push({name:String(a[0]),value:String(a[1])})}):\"object\"==typeof e&&e?Object.keys(e).forEach(function(t){r._list.push({name:String(t),value:String(e[t])})}):(\"?\"===(e=String(e)).substring(0,1)&&(e=e.substring(1)),this._list=o(e))),this._url_object=null,this._setList=function(e){a||(r._list=e)};var a=!1;this._update_steps=function(){a||(a=!0,r._url_object&&(\"about:\"===r._url_object.protocol&&-1!==r._url_object.pathname.indexOf(\"?\")&&(r._url_object.pathname=r._url_object.pathname.split(\"?\")[0]),r._url_object.search=i(r._list),a=!1))}}function l(e,t){var n=0;this.next=function(){if(n>=e.length)return{done:!0,value:void 0};var r=e[n++];return{done:!1,value:\"key\"===t?r.name:\"value\"===t?r.value:[r.name,r.value]}}}function c(t,n){if(!(this instanceof e.URL))throw new TypeError(\"Failed to construct 'URL': Please use the 'new' operator.\");n&&(t=function(){if(r)return new a(t,n).href;var e;try{var i;if(\"[object OperaMini]\"===Object.prototype.toString.call(window.operamini)?((e=document.createElement(\"iframe\")).style.display=\"none\",document.documentElement.appendChild(e),i=e.contentWindow.document):document.implementation&&document.implementation.createHTMLDocument?i=document.implementation.createHTMLDocument(\"\"):document.implementation&&document.implementation.createDocument?((i=document.implementation.createDocument(\"http://www.w3.org/1999/xhtml\",\"html\",null)).documentElement.appendChild(i.createElement(\"head\")),i.documentElement.appendChild(i.createElement(\"body\"))):window.ActiveXObject&&((i=new window.ActiveXObject(\"htmlfile\")).write(\"<head></head><body></body>\"),i.close()),!i)throw Error(\"base not supported\");var o=i.createElement(\"base\");o.href=n,i.getElementsByTagName(\"head\")[0].appendChild(o);var u=i.createElement(\"a\");return u.href=t,u.href}finally{e&&e.parentNode.removeChild(e)}}());var i=function(e){if(r)return new a(e);var t=document.createElement(\"a\");return t.href=e,t}(t||\"\"),l=function(){if(!(\"defineProperties\"in Object))return!1;try{var e={};return Object.defineProperties(e,{prop:{get:function(){return!0}}}),e.prop}catch(e){return!1}}()?this:document.createElement(\"a\"),c=new u(i.search?i.search.substring(1):null);function s(){var e=i.href.replace(/#$|\\?$|\\?(?=#)/g,\"\");i.href!==e&&(i.href=e)}function f(){c._setList(i.search?o(i.search.substring(1)):[]),c._update_steps()}return c._url_object=l,Object.defineProperties(l,{href:{get:function(){return i.href},set:function(e){i.href=e,s(),f()},enumerable:!0,configurable:!0},origin:{get:function(){return\"origin\"in i?i.origin:this.protocol+\"//\"+this.host},enumerable:!0,configurable:!0},protocol:{get:function(){return i.protocol},set:function(e){i.protocol=e},enumerable:!0,configurable:!0},username:{get:function(){return i.username},set:function(e){i.username=e},enumerable:!0,configurable:!0},password:{get:function(){return i.password},set:function(e){i.password=e},enumerable:!0,configurable:!0},host:{get:function(){var e={\"http:\":/:80$/,\"https:\":/:443$/,\"ftp:\":/:21$/}[i.protocol];return e?i.host.replace(e,\"\"):i.host},set:function(e){i.host=e},enumerable:!0,configurable:!0},hostname:{get:function(){return i.hostname},set:function(e){i.hostname=e},enumerable:!0,configurable:!0},port:{get:function(){return i.port},set:function(e){i.port=e},enumerable:!0,configurable:!0},pathname:{get:function(){return\"/\"!==i.pathname.charAt(0)?\"/\"+i.pathname:i.pathname},set:function(e){i.pathname=e},enumerable:!0,configurable:!0},search:{get:function(){return i.search},set:function(e){i.search!==e&&(i.search=e,s(),f())},enumerable:!0,configurable:!0},searchParams:{get:function(){return c},enumerable:!0,configurable:!0},hash:{get:function(){return i.hash},set:function(e){i.hash=e,s()},enumerable:!0,configurable:!0},toString:{value:function(){return i.toString()},enumerable:!1,configurable:!0},valueOf:{value:function(){return i.valueOf()},enumerable:!1,configurable:!0}}),l}if(Object.defineProperties(u.prototype,{append:{value:function(e,t){this._list.push({name:e,value:t}),this._update_steps()},writable:!0,enumerable:!0,configurable:!0},delete:{value:function(e){for(var t=0;t<this._list.length;)this._list[t].name===e?this._list.splice(t,1):++t;this._update_steps()},writable:!0,enumerable:!0,configurable:!0},get:{value:function(e){for(var t=0;t<this._list.length;++t)if(this._list[t].name===e)return this._list[t].value;return null},writable:!0,enumerable:!0,configurable:!0},getAll:{value:function(e){for(var t=[],n=0;n<this._list.length;++n)this._list[n].name===e&&t.push(this._list[n].value);return t},writable:!0,enumerable:!0,configurable:!0},has:{value:function(e){for(var t=0;t<this._list.length;++t)if(this._list[t].name===e)return!0;return!1},writable:!0,enumerable:!0,configurable:!0},set:{value:function(e,t){for(var n=!1,r=0;r<this._list.length;)this._list[r].name===e?n?this._list.splice(r,1):(this._list[r].value=t,n=!0,++r):++r;n||this._list.push({name:e,value:t}),this._update_steps()},writable:!0,enumerable:!0,configurable:!0},entries:{value:function(){return new l(this._list,\"key+value\")},writable:!0,enumerable:!0,configurable:!0},keys:{value:function(){return new l(this._list,\"key\")},writable:!0,enumerable:!0,configurable:!0},values:{value:function(){return new l(this._list,\"value\")},writable:!0,enumerable:!0,configurable:!0},forEach:{value:function(e){var t=arguments.length>1?arguments[1]:void 0;this._list.forEach(function(n,r){e.call(t,n.value,n.name)})},writable:!0,enumerable:!0,configurable:!0},toString:{value:function(){return i(this._list)},writable:!0,enumerable:!1,configurable:!0}}),\"Symbol\"in e&&\"iterator\"in e.Symbol&&(Object.defineProperty(u.prototype,e.Symbol.iterator,{value:u.prototype.entries,writable:!0,enumerable:!0,configurable:!0}),Object.defineProperty(l.prototype,e.Symbol.iterator,{value:function(){return this},writable:!0,enumerable:!0,configurable:!0})),a)for(var s in a)a.hasOwnProperty(s)&&\"function\"==typeof a[s]&&(c[s]=a[s]);e.URL=c,e.URLSearchParams=u}(),function(){if(\"1\"!==new e.URLSearchParams([[\"a\",1]]).get(\"a\")||\"1\"!==new e.URLSearchParams({a:1}).get(\"a\")){var r=e.URLSearchParams;e.URLSearchParams=function(e){if(e&&\"object\"==typeof e&&t(e)){var a=new r;return n(e).forEach(function(e){if(!t(e))throw TypeError();var r=n(e);if(2!==r.length)throw TypeError();a.append(r[0],r[1])}),a}return e&&\"object\"==typeof e?(a=new r,Object.keys(e).forEach(function(t){a.set(t,e[t])}),a):new r(e)}}}()}(self);</script>\n <script>\"use strict\";var get=function(t){return Array.prototype.slice.call(document.querySelectorAll(t))},addFragmentToURLState=function(t){if(!t)return t;var e=new URL(t);if(e&&\"\"!==fragment&&fragment.length<100){var a=window.btoa(JSON.stringify({fragment:\"#\"===fragment[0]?fragment:\"#\".concat(fragment)})),r=e.searchParams.get(\"state\"),n=e.searchParams.get(\"RelayState\");r?e.searchParams.set(\"state\",\"\".concat(r,\".\").concat(a)):n&&e.searchParams.set(\"RelayState\",\"\".concat(n,\".\").concat(a))}return e.toString()},fragment=window.location.hash||\"\",article=document.querySelector(\"#data\"),dset=article.dataset,autoRedirectToIdentity=\"true\"===dset.autoRedirectToIdentity,autoRedirectURL=addFragmentToURLState(dset.autoRedirectUrl),message=dset.message;autoRedirectURL&&autoRedirectToIdentity&&(message||(window.location=autoRedirectURL));</script>\n </head>\n\n <body>\n <div class=\"Content\">\n <div class=\"base_AccessLogo\">\n <svg width=\"339\" height=\"50\" fill=\"none\" viewBox=\"0 0 339 50\"><path d=\"M42.8 2.847A20.9 20.9 0 0 0 30.343 6.97a21.6 21.6 0 0 0-7.703 10.806l-.14.449h3.9l.09-.215a17.76 17.76 0 0 1 7.47-8.88 17.2 17.2 0 0 1 11.254-2.255 17.38 17.38 0 0 1 10.206 5.342 18.02 18.02 0 0 1 4.772 10.642c.374 3.993-.58 8-2.71 11.372a17.56 17.56 0 0 1-9.03 7.217 17.17 17.17 0 0 1-11.469-.038A17.57 17.57 0 0 1 28 34.133c-.1-.153-.19-.306-.28-.47l-.2-.357h-4.09l.24.5q.556 1.22 1.27 2.347a21.4 21.4 0 0 0 8.002 7.497 20.86 20.86 0 0 0 10.59 2.47 20.9 20.9 0 0 0 10.4-3.203 21.47 21.47 0 0 0 7.481-8.038 22 22 0 0 0 2.6-10.763 22 22 0 0 0-2.962-10.664 21.4 21.4 0 0 0-7.75-7.77A20.9 20.9 0 0 0 42.8 2.848\" fill=\"#fff\"/><path d=\"m43.79 21.52-7.43-7.581-2.47 2.52 4.32 4.419H6l2.08 3.56H42.6zM43.74 37.602l-2.47-2.52 4.32-4.419H11.7l-2.07-3.57h40.35l1.19 2.928zM327.359 19.158q1.95 1.248 2.239 4.295h-4.341q-.091-.837-.472-1.325-.717-.883-2.438-.883-1.416 0-2.026.441-.594.442-.594 1.036 0 .746.64 1.082.64.35 4.524 1.203 2.59.609 3.885 1.843 1.28 1.25 1.279 3.123 0 2.467-1.843 4.037-1.828 1.554-5.667 1.554-3.915 0-5.788-1.646-1.859-1.66-1.859-4.22h4.403q.137 1.159.594 1.646.807.868 2.986.868 1.28 0 2.025-.38.762-.381.762-1.143 0-.73-.609-1.112-.609-.38-4.524-1.31-2.818-.7-3.976-1.752-1.158-1.036-1.158-2.985 0-2.3 1.798-3.946 1.812-1.66 5.087-1.66 3.108 0 5.073 1.234M310.929 19.158q1.95 1.248 2.24 4.295h-4.342q-.091-.837-.472-1.325-.716-.883-2.437-.883-1.417 0-2.026.441-.594.442-.594 1.036 0 .746.639 1.082.64.35 4.525 1.203 2.59.609 3.884 1.843 1.28 1.25 1.28 3.123 0 2.467-1.844 4.037-1.827 1.554-5.666 1.554-3.915 0-5.789-1.646-1.858-1.66-1.858-4.22h4.402q.137 1.159.594 1.646.808.868 2.986.868 1.28 0 2.026-.38.761-.381.761-1.143 0-.73-.609-1.112-.609-.38-4.524-1.31-2.818-.7-3.976-1.752-1.158-1.036-1.158-2.985 0-2.3 1.798-3.946 1.812-1.66 5.088-1.66 3.107 0 5.072 1.234M297.272 30.125q-.167 1.478-1.538 3.001-2.133 2.422-5.971 2.422-3.169 0-5.591-2.041t-2.422-6.642q0-4.31 2.178-6.61 2.195-2.3 5.682-2.3 2.072 0 3.732.776 1.66.777 2.742 2.452.975 1.479 1.265 3.428.167 1.142.137 3.29h-11.364q.091 2.499 1.569 3.504.898.624 2.163.624 1.341 0 2.178-.761.457-.411.808-1.143zm-4.295-5.088q-.107-1.72-1.051-2.604-.93-.9-2.316-.9-1.507 0-2.346.945-.822.945-1.035 2.56zM280.997 24.352h-4.448a3.9 3.9 0 0 0-.625-1.675q-.73-1.006-2.27-1.006-2.193 0-3.001 2.178-.426 1.158-.426 3.078 0 1.827.426 2.94.777 2.07 2.925 2.071 1.524 0 2.163-.822.64-.823.777-2.133h4.433q-.153 1.98-1.432 3.747-2.042 2.85-6.047 2.849-4.006 0-5.896-2.376-1.888-2.377-1.888-6.17 0-4.28 2.086-6.657Q269.862 18 273.532 18q3.123 0 5.104 1.401 1.995 1.402 2.361 4.951M264.567 24.352h-4.448a3.85 3.85 0 0 0-.625-1.675q-.731-1.006-2.269-1.006-2.194 0-3.001 2.178-.427 1.158-.427 3.078 0 1.827.427 2.94.777 2.07 2.924 2.071 1.524 0 2.164-.822.64-.823.776-2.133h4.433q-.152 1.98-1.432 3.747-2.04 2.85-6.047 2.849t-5.895-2.376q-1.89-2.377-1.889-6.17 0-4.28 2.087-6.657Q253.431 18 257.103 18q3.123 0 5.103 1.401 1.995 1.402 2.361 4.951M242.09 30.384h-8.272L232.264 35h-4.905l8.013-22.454h5.301L248.625 35h-5.088zm-1.31-3.869-2.803-8.835-2.895 8.835zM219.788 30.125q-.168 1.478-1.539 3.001-2.132 2.422-5.971 2.422-3.168 0-5.59-2.041t-2.422-6.642q0-4.31 2.178-6.61 2.193-2.3 5.682-2.3 2.071 0 3.732.776 1.66.777 2.742 2.452.975 1.479 1.264 3.428.168 1.142.137 3.29h-11.364q.091 2.499 1.569 3.504.9.624 2.164.624 1.34 0 2.178-.761.457-.411.807-1.143zm-4.296-5.088q-.106-1.72-1.051-2.604-.929-.9-2.315-.9-1.508 0-2.346.945-.822.945-1.036 2.56zM202.702 22.402q-2.62 0-3.519 1.706-.503.96-.503 2.956V35h-4.371V18.396h4.143v2.894q1.005-1.66 1.752-2.27 1.218-1.02 3.168-1.02.121 0 .198.015.091 0 .381.015v4.448a12 12 0 0 0-1.249-.076M178.549 20.194q1.72-2.194 5.91-2.194 2.727 0 4.844 1.081 2.118 1.082 2.118 4.083v7.616q0 .792.03 1.92.045.853.259 1.157.213.306.64.503V35h-4.722a4.8 4.8 0 0 1-.275-.944 12 12 0 0 1-.122-1.006 9 9 0 0 1-2.071 1.66q-1.402.808-3.169.808-2.254 0-3.732-1.28-1.462-1.294-1.462-3.656 0-3.06 2.361-4.432 1.295-.747 3.808-1.067l1.478-.182q1.203-.153 1.721-.381.93-.396.929-1.234 0-1.02-.716-1.402-.7-.396-2.071-.396-1.539 0-2.179.762-.456.564-.609 1.523h-4.189q.137-2.178 1.219-3.58m3.229 11.668q.61.503 1.493.503 1.401 0 2.574-.823 1.189-.823 1.234-3v-1.616a5 5 0 0 1-.838.427 7.3 7.3 0 0 1-1.142.29l-.975.182q-1.371.244-1.965.594-1.005.594-1.005 1.843 0 1.113.624 1.6M167.682 12.41v3.534q-.306-.015-.595-.015-.288-.015-.7-.016-1.021 0-1.249.564-.23.564-.198 1.767v.305h2.848v3.061h-2.848V35h-4.327V21.61h-2.422V18.55h2.377v-1.067q0-2.65 1.173-3.945 1.05-1.218 4.28-1.219.396 0 .807.03.412.031.854.062m7.007.137V35h-4.326V12.547zM156.763 12.577V35h-4.219v-2.3q-.93 1.477-2.118 2.148-1.188.67-2.955.67-2.909 0-4.905-2.346-1.98-2.361-1.98-6.047 0-4.25 1.95-6.688Q144.501 18 147.776 18q1.508 0 2.681.67a5.2 5.2 0 0 1 1.904 1.828v-7.92zm-11.699 14.228q0 2.3.914 3.67.9 1.387 2.742 1.387t2.803-1.37q.96-1.372.96-3.55 0-3.046-1.539-4.357a3.3 3.3 0 0 0-2.193-.792q-1.905 0-2.803 1.447-.884 1.432-.884 3.565M134.164 32.654q-.06.075-.304.457a3 3 0 0 1-.579.67q-1.021.915-1.981 1.25-.944.334-2.224.334-3.685 0-4.966-2.65-.715-1.463-.715-4.31V18.395h4.448v10.008q0 1.417.335 2.133.594 1.264 2.33 1.264 2.225 0 3.047-1.797.426-.976.426-2.575v-9.033h4.403V35h-4.22zM119.227 20.498q2.102 2.636 2.102 6.23 0 3.657-2.102 6.261-2.102 2.59-6.383 2.59-4.28 0-6.382-2.59-2.103-2.604-2.103-6.26 0-3.596 2.103-6.23 2.101-2.636 6.382-2.636t6.383 2.635m-6.398 1.036q-1.905 0-2.94 1.356-1.02 1.34-1.021 3.838t1.021 3.854q1.035 1.356 2.94 1.356 1.903 0 2.925-1.356 1.02-1.356 1.02-3.854t-1.02-3.838q-1.022-1.356-2.925-1.356M97.727 12.546h4.341V35h-4.341zM92.22 33.324q-2.514 2.3-6.429 2.3-4.844 0-7.616-3.107-2.773-3.123-2.773-8.56 0-5.88 3.154-9.064 2.742-2.773 6.976-2.773 5.667 0 8.287 3.717 1.448 2.087 1.554 4.189H90.68q-.457-1.614-1.173-2.437-1.28-1.463-3.793-1.463-2.56 0-4.037 2.072-1.477 2.057-1.477 5.834 0 3.778 1.553 5.667 1.57 1.875 3.976 1.874 2.468 0 3.763-1.615.716-.868 1.188-2.605h4.646q-.609 3.671-3.108 5.971\" fill=\"#fff\"/></svg>\n </div>\n\n <div class=\"AuthBox\">\n <div class=\"AuthBox-body\">\n <a class=\"OrgAvatarLink\" href=''>\n <div class=\"OrgAvatarLink-logo\">\n <img src=\"https://s.cystack.net/resource/cystack/CyStack-Black.svg\" style=\"opacity:0;\" onload=\"this.style.opacity='1'\">\n </div>\n <div class=\"OrgAvatarLink-title\">\n CyStack\n </div>\n </a>\n <div class=\"AuthBox-App\">\n <h1 class=\"Card-title\">\n Log in to CyStack Blog\n </h1>\n\n </div>\n <div class=\"AuthBox-Normal\">\n <div class=\"AuthBox-AuthGroup\">\n <div class=\"AuthBox-text\">\n Sign in with:\n </div>\n <div class=\"AuthServiceLogin\">\n <div class=\"AuthServiceLogin-row AuthServiceLogin-row-is-only\">\n <a class=\"Button-is-block Button Button-is-auth js-idp\" data-idp=\"Google\" title=\"Google ・ CyStack\"\n href=\"https://accounts.google.com/o/oauth2/auth?client_id=306229843697-8ot9f4phmrpr35gahbe3cvf5agj6nhs6.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fcystack.cloudflareaccess.com%2Fcdn-cgi%2Faccess%2Fcallback&response_type=code&state=56d60f4602fb537ccc9e652b85690cd92e11ca9f683c0c4be3e291dac891de4f.JTdCJTIyaWF0JTIyJTNBMTc4NzU0ODgwMyUyQyUyMmF1dGhEb21haW4lMjIlM0ElMjJjeXN0YWNrLmNsb3VkZmxhcmVhY2Nlc3MuY29tJTIyJTJDJTIyaG9zdG5hbWUlMjIlM0ElMjJibG9nLmN5c3RhY2sub3JnJTIyJTJDJTIycmVkaXJlY3RVUkwlMjIlM0ElMjIlMkZsYWJzJTJGd3AtanNvbiUyRndwJTJGcmFua21hdGglMkZ2MSUyRmdldEhlYWQlM0Z1cmwlM0RodHRwcyUzQSUyNTJGJTI1MkZibG9nLmN5c3RhY2sub3JnJTI1MkZsYWJzJTI1MkZ2aSUyNTJGMjAyNiUyNTJGMDYlMjUyRjE5JTI1MkZjdmUtMjAyNi00MjUzMC1uZ2lueC12aSUyNTJGJTIyJTJDJTIyYXVkJTIyJTNBJTIyZDA4Y2MzMTJkMzU4MDI2OGRmM2FjYTI0Y2I0ZjRiNzQ2YWE1NThlZDBhMzg0Y2I0ZDczZGQ3NjhlYjAyMDFmNyUyMiUyQyUyMmlzU2FtZVNpdGVOb25lQ29tcGF0aWJsZSUyMiUzQXRydWUlMkMlMjJpc0lEUFRlc3QlMjIlM0FmYWxzZSUyQyUyMmlzUmVmcmVzaCUyMiUzQWZhbHNlJTJDJTIybm9uY2UlMjIlM0ElMjJuUjl0cWlVUWJNekdGY3pDeSUyMiUyQyUyMmlkcElkJTIyJTNBJTIyODkzNTUzZjYtMjA1Yy00Y2NjLTljMWUtYzMwOTQ4ZTdmODVjJTIyJTJDJTIyc2VydmljZV90b2tlbl9zdGF0dXMlMjIlM0FmYWxzZSUyQyUyMmF1dGhfc3RhdHVzJTIyJTNBJTIyTk9ORSUyMiUyQyUyMmlzX3dhcnAlMjIlM0FmYWxzZSUyQyUyMmlzX2dhdGV3YXklMjIlM0FmYWxzZSUyQyUyMm10bHNfYXV0aCUyMiUzQSU3QiUyMmNlcnRfaXNzdWVyX2RuJTIyJTNBJTIyJTIyJTJDJTIyY2VydF9zZXJpYWwlMjIlM0ElMjIlMjIlMkMlMjJjZXJ0X2lzc3Vlcl9za2klMjIlM0ElMjIlMjIlMkMlMjJjZXJ0X3ByZXNlbnRlZCUyMiUzQWZhbHNlJTJDJTIyY29tbW9uX25hbWUlMjIlM0ElMjIlMjIlMkMlMjJhdXRoX3N0YXR1cyUyMiUzQSUyMk5PTkUlMjIlN0QlMkMlMjJhcHBTZXNzaW9uSGFzaCUyMiUzQSUyMmQ2ZmU3NjU3ZTRkMTQ0MmI1OGVkYzhkNGU5MTFiOGZmOWEzZTI2NTkzNWNmNThiNzZjNjk3NzgxYjNmODg5MmIlMjIlN0Q%253D&scope=email+profile+openid\" accesskey=\"1\" id=\"idp1\">\n <div class=\"Button-auth-service-icon\"><svg viewBox=\"0 0 256 262\"><path d=\"M13.925 71.947C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602C35.393 231.798 79.49 261.1 130.55 261.1c35.248 0 64.839-11.605 86.453-31.622 24.659-22.774 38.875-56.282 38.875-96.027 0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356-11.024 7.688-25.82 13.055-45.257 13.055-34.523 0-63.824-22.773-74.269-54.25-2.756-8.123-4.351-16.827-4.351-25.82 0-8.994 1.595-17.697 4.206-25.82 10.59-31.477 39.891-54.251 74.414-54.251 24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0 79.49 0 35.393 29.301 13.925 71.947z\"></path></svg></div>\n <div class=\"AuthBoxRow--name\">Google ・ CyStack</div>\n </a>\n </div>\n </div>\n </div>\n <div class=\"kumo-divider\" role=\"separator\" aria-orientation=\"horizontal\">\n <span class=\"kumo-divider__label\">or</span>\n </div>\n <div class=\"AuthBox-RequestCode AuthBox-RequestCode__idpsExist\">\n <form class=\"AuthFormLogin\" action='https://cystack.cloudflareaccess.com/cdn-cgi/access/verify-code/blog.cystack.org?kid=d08cc312d3580268df3aca24cb4f4b746aa558ed0a384cb4d73dd768eb0201f7&meta=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ijk5MWY5NGIwZTQ2NTZlZWU2NTM5ZjdkYTUwMDQ2NDIxMTkyZjQ3YzkzYmMxMDk5ZTNhZGQwMzQwMGQ1NjhlZTUifQ.eyJ0eXBlIjoibWV0YSIsImF1ZCI6ImQwOGNjMzEyZDM1ODAyNjhkZjNhY2EyNGNiNGY0Yjc0NmFhNTU4ZWQwYTM4NGNiNGQ3M2RkNzY4ZWIwMjAxZjciLCJob3N0bmFtZSI6ImJsb2cuY3lzdGFjay5vcmciLCJyZWRpcmVjdF91cmwiOiIvbGFicy93cC1qc29uL3dwL3JhbmttYXRoL3YxL2dldEhlYWQ_dXJsPWh0dHBzOiUyRiUyRmJsb2cuY3lzdGFjay5vcmclMkZsYWJzJTJGdmklMkYyMDI2JTJGMDYlMkYxOSUyRmN2ZS0yMDI2LTQyNTMwLW5naW54LXZpJTJGIiwic2VydmljZV90b2tlbl9zdGF0dXMiOmZhbHNlLCJpc193YXJwIjpmYWxzZSwiaXNfZ2F0ZXdheSI6ZmFsc2UsImV4cCI6MTc4NzU0OTEwMiwibmJmIjoxNzg3NTQ4ODAyLCJpYXQiOjE3ODc1NDg4MDIsImF1dGhfc3RhdHVzIjoiTk9ORSIsIm10bHNfYXV0aCI6eyJjZXJ0X2lzc3Vlcl9kbiI6IiIsImNlcnRfc2VyaWFsIjoiIiwiY2VydF9pc3N1ZXJfc2tpIjoiIiwiY2VydF9wcmVzZW50ZWQiOmZhbHNlLCJjb21tb25fbmFtZSI6IiIsImF1dGhfc3RhdHVzIjoiTk9ORSJ9LCJyZWFsX2NvdW50cnkiOiJTRyIsImFwcF9zZXNzaW9uX2hhc2giOiJkNmZlNzY1N2U0ZDE0NDJiNThlZGM4ZDRlOTExYjhmZjlhM2UyNjU5MzVjZjU4Yjc2YzY5Nzc4MWIzZjg4OTJiIn0.btJgTThF7X4MGTNXBVH0BOW-Q1Ew190yRlcUkb1RVoK8-r62TvKolDhZ6JaCOH89Flhmf5qWIRZGYp_EJgrRcubozESImWsafPMoWnYYGgxyskXpiM4YLDzIq_Q4zzBvT8PzQ2DkJ7EQFg28jXIGDk4p-LymziQFsKRpOKfDIIp0eaz_fNxogICG1wpRMSOujXX2F_mebgfhO3z4YcnBSSlM9l3cyac_3v1hK6gDCGRzEH091W_P4cdxduCcDgEFUFYhYQXSCb1DTH7TIHWrn5V-hZlaDErldvu4kHIgQc3oeC-eZJVcUPwDqMma5lwm8fXuNBtrovVjRKGqkZTyZA&redirect_url=%2Flabs%2Fwp-json%2Fwp%2Frankmath%2Fv1%2FgetHead%3Furl%3Dhttps%3A%252F%252Fblog.cystack.org%252Flabs%252Fvi%252F2026%252F06%252F19%252Fcve-2026-42530-nginx-vi%252F' method=\"post\" id=\"totp-form\">\n <div class=\"AuthFormLogin-row\">\n <label for=\"email\">Email</label>\n <input id=\"email\" class=\"StandardInput-is-block StandardInput EmailInput\" type=\"email\" required\n placeholder=\"example@email.com\" spellcheck=\"false\" autocomplete=\"off\" autocapitalize=\"none\"\n name=\"email\">\n <input hidden type=\"text\" name=\"client_id\" value=''>\n <input hidden type=\"text\" name=\"connector_id\" value=''>\n <input hidden type=\"text\" name=\"connector_type\" value=''>\n <input hidden type=\"text\" name=\"redirect_url\" value=''>\n </div>\n <div class=\"AuthFormLogin-row\">\n <button type=\"submit\" form=\"totp-form\" class=\"Button-is-block Button Button-is-primary\">\n Send login code\n </button>\n </div>\n </form>\n </div>\n\n </div>\n </div>\n </div>\n </div>\n\n <script>\"use strict\";if(document.addEventListener(\"keyup\",function(e){if(\"BODY\"===e.target.nodeName&&e.key>=1&&e.key<=10){var t=document.getElementById(\"idp\"+e.key);window.location=t.getAttribute(\"href\")}},!1),\"\"!==fragment&&fragment.length<100){var services=get(\".js-idp\")||[];services.map(function(e){return e.href=addFragmentToURLState(e.href),e})}</script>\n </body>\n\n</html>"
Xem bản tiếng Anh tại đây / Read the English version
Tóm tắt
nginx là một trong những thành phần hạ tầng được triển khai rộng rãi nhất trên Internet, đứng trước hàng triệu website và là reverse proxy mặc định của vô số nền tảng cloud. Từ phiên bản 1.25.0, nginx hỗ trợ HTTP/3 ngay trong nhân thay vì qua một bản vá ngoài luồng, nghĩa là toàn bộ bề mặt tấn công mới của QUIC và QPACK chạy thẳng trong worker process xử lý mọi kết nối.
Trong quá trình rà soát phần xử lý QPACK của nginx HTTP/3, tôi phát hiện một lỗi use-after-free (UAF) mà một kẻ tấn công từ xa, không cần xác thực, có thể kích hoạt chỉ sau khi hoàn tất một QUIC handshake. Ở mức cơ bản, lỗi làm sập worker process. Ở mức cao hơn, với một chút sắp xếp bộ nhớ (heap grooming), lỗi này cho ra một điều kiện ghi có kiểm soát (write-what-where) hoạt động trước khi bất kỳ logic ứng dụng nào chạy.
Gốc rễ của lỗi là sự lệch pha vòng đời. Một con trỏ thuộc về phiên HTTP/3, vốn sống suốt thời gian kết nối, lại nắm giữ vùng nhớ thuộc về một luồng đơn hướng (unidirectional stream) vốn chỉ sống trong khoảnh khắc. Khi luồng đó đóng lại, vùng nhớ được giải phóng, nhưng con trỏ cấp phiên thì vẫn còn và vẫn được coi là hợp lệ. Theo cách mô tả trong advisory của F5, kẻ tấn công dùng một HTTP/3 session được dựng có chủ đích để tái mở (reopen) một QPACK encoder stream, từ đó kích hoạt use-after-free trong worker.
Lỗ hổng đã được F5 công bố ngày 17/06/2026 với mã CVE-2026-42530, mã nội bộ NPS-8, xếp loại High theo CVSS v3.1 (8.1) và Critical theo CVSS v4.0 (9.2), và được vá trong NGINX Open Source 1.31.2. Đây là một lỗi thuần ở data plane, advisory ghi rõ không có ảnh hưởng tới control plane.
Bối cảnh
HTTP/3 nén header bằng QPACK (RFC 9204), tương tự HPACK trong HTTP/2 nhưng được thiết kế lại để QUIC có thể giao các luồng không theo thứ tự mà không gây lỗi. QPACK duy trì một bảng động (dynamic table) dùng chung cho cả kết nối: một danh sách các cặp header tên/giá trị mà hai đầu tham chiếu bằng chỉ số thay vì gửi lại nguyên chuỗi.
Việc cập nhật bảng động không đi kèm từng request. Thay vào đó, bên gửi header mở một luồng đơn hướng riêng gọi là QPACK encoder stream (loại luồng 0x02) rồi đẩy các chỉ thị cập nhật bảng qua đó. Với nginx ở vai trò server, client chính là bộ mã hóa (encoder), còn nginx là bộ giải mã (decoder). Các chỉ thị mà nginx phải xử lý gồm Set Dynamic Table Capacity, Insert With Name Reference, Insert With Literal Name và Duplicate.
Phần mấu chốt nằm ở vòng đời của các đối tượng. Trong nginx, bảng động thuộc về phiên HTTP/3, lưu trong cấu trúc ngx_http_v3_session_t (gọi tắt là h3c). Phiên này sống suốt thời gian kết nối QUIC tồn tại. Trong khi đó, mỗi luồng đơn hướng lại là một ngx_connection_t độc lập, với một vùng nhớ (memory pool) riêng. Khi luồng đóng lại, pool của nó bị hủy. Hai vòng đời này lệch nhau, và đó chính là gốc rễ của lỗ hổng.
Nguyên nhân gốc rễ
Khi nginx xử lý một chỉ thị Insert, cần một buffer tạm để ráp entry trước khi đưa vào bảng. Buffer này được lấy từ hàm ngx_http_v3_get_insert_buffer() trong src/http/v3/ngx_http_v3_table.c:
ngx_buf_t *
ngx_http_v3_get_insert_buffer(ngx_connection_t *c)
{
ngx_http_v3_session_t *h3c;
ngx_http_v3_dynamic_table_t *dt;
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
if (dt->insert_buffer == NULL) {
dt->insert_buffer = ngx_create_temp_buf(c->pool, dt->capacity);
...
}
dt->insert_buffer->last = dt->insert_buffer->pos;
return dt->insert_buffer;
}
Hãy chú ý dòng cấp phát. dt->insert_buffer là một trường của bảng động, tức sống theo phiên h3c. Nhưng buffer lại được tạo từ c->pool, mà c ở đây là kết nối của encoder stream đầu tiên chạm tới hàm này. Pool của một luồng đơn hướng có vòng đời ngắn hơn nhiều so với phiên. Nói cách khác, một con trỏ cấp phiên đang nắm giữ vùng nhớ thuộc về một luồng.
Khi encoder stream đóng, ngx_http_v3_close_uni_stream() trong src/http/v3/ngx_http_v3_uni.c hủy pool của nó:
static void
ngx_http_v3_close_uni_stream(ngx_connection_t *c)
{
ngx_pool_t *pool;
...
pool = c->pool;
ngx_close_connection(c);
ngx_destroy_pool(pool);
}
ngx_destroy_pool() trả toàn bộ khối nhớ của pool về allocator. ngx_buf_t mà dt->insert_buffer đang trỏ tới nằm trong khối đó, nên giờ nó là vùng nhớ đã giải phóng. Nhưng không có dòng nào đặt lại dt->insert_buffer = NULL. Con trỏ vẫn còn, vẫn khác NULL, và vẫn được coi là hợp lệ.
Khi một encoder stream thứ hai gửi tiếp một chỉ thị Insert, nginx lại gọi ngx_http_v3_get_insert_buffer(). Lần này dt->insert_buffer khác NULL nên nhánh cấp phát bị bỏ qua. Hàm đi thẳng xuống dt->insert_buffer->last = dt->insert_buffer->pos, dereference một ngx_buf_t đã chết. Đây là use-after-free kinh điển: một đối tượng vòng đời dài giữ con trỏ vào bộ nhớ vòng đời ngắn.
Tái hiện lỗi cơ bản
Chuỗi kích hoạt rất ngắn. Sau khi hoàn tất QUIC handshake, client làm ba việc:
- Mở encoder stream thứ nhất, gửi Set Dynamic Table Capacity rồi một chỉ thị Insert. Chỉ thị Insert đầu tiên này buộc nginx cấp phát
insert_buffer từ pool của luồng.
- Để luồng thứ nhất đóng lại, khiến pool của nó bị hủy và
ngx_buf_t bị giải phóng.
- Mở encoder stream thứ hai và gửi một chỉ thị Insert nữa, làm nginx dereference con trỏ treo.
sequenceDiagram
participant A as Kẻ tấn công
participant S1 as Encoder stream 1
participant H3C as Phiên HTTP/3
participant S2 as Encoder stream 2
A->>S1: Set Dynamic Table Capacity + Insert
S1->>H3C: get_insert_buffer cấp ngx_buf_t từ pool của stream 1
Note over S1,H3C: insert_buffer trỏ vào pool của stream 1
A->>S1: Đóng stream 1
Note over S1: ngx_destroy_pool huỷ pool, ngx_buf_t bị giải phóng
Note over H3C: insert_buffer trở thành con trỏ treo
A->>S2: Insert, tái mở encoder stream
S2->>H3C: get_insert_buffer thấy insert_buffer khác NULL
Note over H3C: dereference vùng nhớ đã giải phóng, UAF
Toàn bộ payload nằm gọn dưới 40 byte dữ liệu sau handshake. Trên một bản build có AddressSanitizer, lần truy cập đọc tại dòng 174 cho ra báo cáo rõ ràng:
==8==ERROR: AddressSanitizer: heap-use-after-free on address 0x529000028410
READ of size 8 at 0x529000028410 thread T0
#0 ngx_http_v3_get_insert_buffer src/http/v3/ngx_http_v3_table.c:174
#1 ngx_http_v3_parse_field_inr src/http/v3/ngx_http_v3_parse.c:1503
#2 ngx_http_v3_parse_encoder src/http/v3/ngx_http_v3_parse.c:1422
#3 ngx_http_v3_parse_uni src/http/v3/ngx_http_v3_parse.c:1954
#4 ngx_http_v3_uni_read_handler src/http/v3/ngx_http_v3_uni.c:227
freed by thread T0 here:
#0 free
#1 ngx_destroy_pool src/core/ngx_palloc.c:90
#2 ngx_http_v3_close_uni_stream src/http/v3/ngx_http_v3_uni.c:100
Stack của lần cấp phát và lần giải phóng khớp đúng với mô tả ở trên: vùng nhớ được free qua ngx_destroy_pool gọi từ ngx_http_v3_close_uni_stream, rồi được dùng lại trong ngx_http_v3_get_insert_buffer qua đường parse encoder stream. Trên một bản build glibc thông thường ở mức tối ưu -O2 và không có sanitizer, cùng chuỗi đó làm hỏng metadata của heap allocator và worker chết với thông báo corrupted double-linked list. Đây đã là một lỗi từ chối dịch vụ từ xa, không cần xác thực: mỗi lần kích hoạt làm sập một worker và kéo theo toàn bộ kết nối đang chạy trên worker đó.
Khai thác
Một crash đã đủ nghiêm trọng, nhưng cấu trúc của lỗi này còn cho thấy điều đáng lo hơn. insert_buffer không phải một vùng dữ liệu trơn. Nó là một ngx_buf_t, mà ngx_buf_t về bản chất là một tập con trỏ mô tả một đoạn nhớ:
typedef struct ngx_buf_s {
u_char *pos;
u_char *last;
off_t file_pos;
off_t file_last;
u_char *start;
u_char *end;
...
};
Quá trình xử lý Insert sẽ ghi các byte tên và giá trị của header vào buffer thông qua chính các con trỏ này, đại khái là *buf->last++ = ... cho tới khi chạm buf->end. Nếu kẻ tấn công kiểm soát được nội dung của ngx_buf_t đã chết, họ kiểm soát luôn đích đến của những lần ghi đó.
Đây là lúc heap grooming vào cuộc. Khối pool vừa được giải phóng nằm ở một size class cụ thể của allocator. Nếu ngay sau bước free, kẻ tấn công làm nginx cấp phát một vùng cùng size class với nội dung do mình điều khiển, allocator nhiều khả năng trả lại đúng khối vừa free, và nội dung tấn công sẽ nằm chồng lên cái xác ngx_buf_t. Một body request có kích thước phù hợp là ứng viên hoàn hảo cho việc tái cấp phát này, vì nó được sao chép gần như nguyên văn vào một buffer mà nginx lấy từ pool.
PoC dựng một ngx_buf_t giả bằng cách đặt giá trị vào đúng offset của struct: pos và last cùng trỏ tới địa chỉ đích, start trỏ tới đầu vùng đích, còn end trỏ tới đích cộng với một span ghi được:
def fake_buf_payload(total_len, fake_offset, target, span):
payload = bytearray(b"P" * total_len)
pos = target.to_bytes(8, "little")
end = (target + span).to_bytes(8, "little")
payload[fake_offset + 0 : fake_offset + 8] = pos # buf->pos
payload[fake_offset + 8 : fake_offset + 16] = pos # buf->last
payload[fake_offset + 32 : fake_offset + 40] = pos # buf->start
payload[fake_offset + 40 : fake_offset + 48] = end # buf->end
return bytes(payload)
Sau khi cái xác đã bị ghi đè bằng buffer giả, encoder stream thứ hai gửi một Insert With Name Reference mang theo một giá trị literal. nginx tin tưởng buf->last và buf->end, rồi chép giá trị literal vào địa chỉ đích. Độ dài ghi được giới hạn bởi large_client_header_buffers.size, tức tới vài kilobyte payload do kẻ tấn công chọn, đặt vào địa chỉ do kẻ tấn công chọn. Cả địa chỉ lẫn nội dung đều nằm trong tay attacker.
flowchart TD
A[Encoder stream 1 gửi Insert] --> B[insert_buffer cấp từ pool của stream 1]
B --> C[Đóng stream 1, pool được giải phóng]
C --> D[Gửi request body cùng size class với khối vừa free]
D --> E[Allocator trả lại đúng khối vừa giải phóng]
E --> F[Body ghi đè ngx_buf_t giả, pos last end trỏ tới đích]
F --> G[Encoder stream 2 gửi Insert mang giá trị literal]
G --> H[nginx ghi literal qua buf-last tới địa chỉ đích]
H --> I[Đạt ghi có kiểm soát write-what-where]
Thời điểm khai thác ở đây đáng chú ý. Phương pháp này hoạt động trên QPACK encoder stream, vốn là một phần của tầng vận chuyển HTTP/3. Phương pháp này không chờ một virtual host, một location, hay một handler ứng dụng nào. Mã ghi chạy ngay sau handshake, trên mọi cấu hình bật HTTP/3, bất kể phía sau nginx phục vụ gì.
Tác động
Đây là một lỗi remote, không cần xác thực, ở mức cơ bản đã đủ để làm sập worker. Nhưng với điều kiện ghi có kiểm soát mô tả ở trên, ranh giới giữa “sập worker” và “thực thi mã” mỏng hơn nhiều so với vẻ ngoài.
Một write-what-where trong không gian địa chỉ của nginx worker là tiền đề rất mạnh cho thực thi mã từ xa. Worker process có đủ các mục tiêu quen thuộc: con trỏ hàm trong các cấu trúc handler, các entry trong GOT, các ngx_buf_t và chuỗi cleanup khác trên heap. Ghi đè một trong số đó rồi để luồng xử lý bình thường dereference là con đường tiêu chuẩn để chuyển một “write-what-where” thành kiểm soát luồng thực thi.
Rào cản còn lại là ASLR. Vì phương pháp này ghi tới một địa chỉ tuyệt đối, kẻ tấn công cần biết ghi vào đâu, nghĩa là cần định vị được heap hoặc vùng mã của worker. Bản thân lỗ hổng không rò rỉ địa chỉ, nên việc vũ khí hóa thành RCE đầy đủ phụ thuộc vào một bước phá ASLR riêng, chẳng hạn một info leak đi kèm hoặc tính dự đoán được của layout heap trong worker đã chạy lâu. Tôi không trình diễn chuỗi RCE hoàn chỉnh trong báo cáo này, nhưng với một kỹ thuật mạnh như vậy chạy trước cả tầng ứng dụng, đây là lý do điểm tác động về tính toàn vẹn (Integrity) và tính sẵn sàng (Availability) đều ở mức High.
Xét về điểm số, F5 chấm lỗ hổng ở mức High với 8.1 theo CVSS v3.1, và Critical với 9.2 theo CVSS v4.0. Advisory mô tả việc khai thác cần thêm các điều kiện nằm ngoài tầm kiểm soát của kẻ tấn công, và điều này phản ánh đúng thực tế: việc tái cấp phát trúng khối nhớ vừa giải phóng phụ thuộc trạng thái heap mà kẻ tấn công không kiểm soát hoàn toàn, nên độ phức tạp tấn công được tính ở mức cao. Dù vậy đây vẫn là một lỗi remote không cần xác thực với hệ quả trải từ sập dịch vụ tới khả năng thực thi mã, và F5 lưu ý nó hoàn toàn nằm ở data plane chứ không chạm tới control plane.
Bản vá
nginx vá lỗi trong bản 1.31.2 phát hành ngày 17/06/2026, và cách họ sửa đi thẳng vào gốc rễ vòng đời thay vì chỉ chữa triệu chứng.
Thay đổi cốt lõi nằm trong chính ngx_http_v3_get_insert_buffer(). Buffer giờ được cấp từ pool của kết nối QUIC cha thay vì pool của luồng đơn hướng:
ngx_buf_t *
ngx_http_v3_get_insert_buffer(ngx_connection_t *c)
{
ngx_http_v3_session_t *h3c;
ngx_http_v3_srv_conf_t *h3scf;
ngx_http_v3_dynamic_table_t *dt;
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
if (dt->insert_buffer == NULL) {
h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module);
dt->insert_buffer = ngx_create_temp_buf(c->quic->parent->pool,
h3scf->max_table_capacity);
if (dt->insert_buffer == NULL) {
return NULL;
}
}
dt->insert_buffer->last = dt->insert_buffer->pos;
return dt->insert_buffer;
}
c->quic->parent là kết nối QUIC chính, tức kết nối sở hữu toàn bộ phiên HTTP/3, chứ không phải luồng đơn hướng tạm thời. Pool của nó sống đúng bằng vòng đời của phiên, nên insert_buffer giờ có vòng đời khớp với bảng động đang giữ nó. Khi một luồng encoder đóng lại, pool bị hủy không còn chứa buffer, và con trỏ không bao giờ treo nữa. Đây là cách sửa đúng về mặt cấu trúc: gắn vùng nhớ vào đối tượng có cùng vòng đời với trạng thái cần phục vụ.
Trong bản đã vá, nginx cũng chặn ngay con đường tái mở luồng. Hàm đăng ký luồng đơn hướng dùng một bitmask created_streams để từ chối mở lại một loại luồng đã từng được tạo trên cùng phiên:
if (index >= 0) {
if (h3c->created_streams & (1 << index)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream already created");
return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
}
h3c->known_streams[index] = c;
h3c->created_streams |= 1 << index;
...
}
Khác với known_streams vốn được xóa khi luồng đóng, bit trong created_streams được giữ nguyên suốt phiên. Một client cố mở lại encoder stream sau khi luồng đầu đã đóng sẽ nhận lỗi H3_STREAM_CREATION_ERROR thay vì chạm tới get_insert_buffer lần thứ hai. Điều này đúng theo tinh thần RFC 9204, vốn coi mỗi loại luồng đơn hướng là duy nhất trên một kết nối, và điều này loại bỏ chính bước “tái mở” mà advisory của F5 nhắc tới.
Mô tả trong changelog của nginx 1.31.2 ngắn gọn như sau:
Security: use-after-free might occur when using HTTP/3 and processing a specially crafted QUIC session, allowing an attacker to cause worker process memory corruption or segmentation fault in a worker process (CVE-2026-42530). Thanks to Trung Nguyen of CyStack.
Người dùng nên nâng cấp lên NGINX Open Source 1.31.2 hoặc mới hơn. Các sản phẩm đóng gói lại nginx như NGINX Instance Manager, NGINX Gateway Fabric và NGINX Ingress Controller cũng nằm trong diện ảnh hưởng theo advisory của F5 và cần theo dõi bản vá tương ứng. Với hệ thống chưa thể nâng cấp ngay, cách giảm thiểu tạm thời theo khuyến nghị của F5 là tắt HTTP/3 bằng cách bỏ tham số quic khỏi mọi directive listen.
Dòng thời gian
- 2026-05-17: Xác định lỗi trên nhánh mainline 1.31.0.
- 2026-05-18: Reproducer ASAN và reproducer làm sập worker trên glibc đều ổn định trên cả 1.31.0 lẫn master. Báo cáo được gửi tới F5 qua GitHub Security Advisory (GHSA-g9jp-cv3q-76p8). F5 SIRT phản hồi tiếp nhận ngay trong ngày, đội phát triển nginx sau đó xác nhận và tái hiện được lỗi.
- 2026-06-17: F5 công bố advisory K000161616, đăng ký CVE-2026-42530 và phát hành bản vá trong NGINX Open Source 1.31.2.
Tài liệu tham khảo