กลับ
2026/11/10
Kyverno CVE-2026-124440: เมื่อ Policy Engine กลายเป็นทางลัดสู่สิทธิ์ผู้ดูแลคลัสเตอร์
ใน Kyverno 1.19.1 tenant ที่เขียน policy ได้เพียงใน namespace เดียวสามารถได้สิทธิ์ผู้ดูแลคลัสเตอร์ บทความนี้อธิบายวิธีการบายพาสและสิ่งที่ควรตรวจสอบก่อนอัปเกรด
หลายทีมใช้ Kyverno เพื่อแยก tenant ใน Kubernetes ออกจากกัน Kyverno ตรวจสอบทุกออบเจ็กต์ตาม policy ก่อนที่ API server จะจัดเก็บ และสามารถอนุญาตให้เจ้าของ namespace เขียน policy สำหรับ namespace ของตนเองได้ CVE-2026-124440 ซึ่งเผยแพร่เมื่อวันที่ 8 พฤศจิกายน 2026 แสดงให้เห็นว่าการมอบสิทธิ์ลักษณะนี้ล้มเหลวได้อย่างไร ใน Kyverno 1.19.1 tenant ที่สร้าง policy ได้เฉพาะใน namespace ของตนเองสามารถทำให้ Kyverno ดำเนินการนอก namespace นั้น และค่อย ๆ ไต่ระดับจนได้สิทธิ์ผู้ดูแลคลัสเตอร์
การแก้ไขมีให้ใช้แล้วตั้งแต่วันที่ 20 ตุลาคมใน Kyverno 1.19.2 คลัสเตอร์ที่ข้ามรุ่นนั้นไปยังคงมีความเสี่ยงอยู่ บทความนี้อธิบายว่าเกิดข้อผิดพลาดตรงไหน การยกระดับสิทธิ์ทำงานอย่างไร และสิ่งที่ควรตรวจสอบในคลัสเตอร์ของคุณ
ประเด็นสำคัญ
- CVE-2026-124440 (GitHub advisory GHSA-39w8-hv5g-f73w) ส่งผลกระทบต่อ Kyverno 1.19.1 และได้รับการแก้ไขแล้วใน 1.19.2 ระเบียน CVE ให้คะแนน 9.4 ตาม CVSS 4.0 และ 9.9 ตาม CVSS 3.1
- ผู้โจมตีต้องการเพียงสิทธิ์ในการสร้าง Kyverno Policy ระดับ namespace ใน namespace ของตนเอง
- apiCall ของ policy ทำงานในฐานะ ServiceAccount ของ admission controller ของ Kyverno ซึ่งอ่านข้อมูลใน namespace อื่นได้และสร้าง admission webhook ระดับทั้งคลัสเตอร์ได้ เส้นทางนี้นำไปสู่สิทธิ์ผู้ดูแลคลัสเตอร์
- advisory ไม่ได้ระบุวิธีแก้ปัญหาเฉพาะหน้าไว้ ให้อัปเกรดเป็น 1.19.2 จากนั้นทบทวนว่าใครสร้าง policy ได้บ้างและมี webhook ใดอยู่บ้าง
- จากแหล่งข้อมูลที่เราตรวจสอบ ยังไม่มีรายงานการโจมตีจริง
กลไกจำกัด namespace ควรทำหน้าที่อะไร
policy ของ Kyverno สามารถดึงข้อมูลจาก Kubernetes API ระหว่างประเมินคำขอได้ ฟีเจอร์นี้เรียกว่า apiCall: กฎจะระบุ urlPath แล้ว Kyverno เรียก API server และนำผลลัพธ์มาใช้ในกฎ การเรียกนี้ใช้ ServiceAccount ของ Kyverno เอง ไม่ใช่สิทธิ์ของผู้เขียน policy
สำหรับ ClusterPolicy ที่มีผลทั้งคลัสเตอร์และเขียนโดยผู้ดูแลแพลตฟอร์ม นี่เป็นพฤติกรรมที่คาดไว้ แต่สำหรับ Policy ระดับ namespace ซึ่งอาจอนุญาตให้ tenant เขียนได้ นี่คือความเสี่ยง advisory ก่อนหน้านี้ (GHSA-c5qq-7g2q-cpqp และ GHSA-5qq8-67g6-4h2w) แสดงให้เห็นว่า Policy ระดับ namespace สามารถใช้ apiCall เพื่ออ่าน namespace อื่นหรือเขียนออบเจ็กต์ระดับคลัสเตอร์ได้ Kyverno 1.19.1 ซึ่งออกเมื่อวันที่ 10 กันยายน 2026 จึงเพิ่ม “namespace clamp” (กลไกจำกัด namespace): ก่อนเรียก API Kyverno จะตรวจสอบว่าพาธยังอยู่ภายใน namespace ของ policy เอง
จุดที่การตรวจสอบกับการทำงานจริงไม่ตรงกัน
กลไกจำกัดใน 1.19.1 ไม่ได้ตรวจสอบสตริงที่ส่งออกไปจริง ตามที่ advisory ระบุ กลไกนี้ถอดรหัส percent-encoding ใน urlPath ทำให้ผลลัพธ์เป็นรูปแบบมาตรฐาน (เพื่อให้ส่วน .. ถูกแปลงแล้ว) และตรวจสอบ namespace ในสำเนาที่ทำความสะอาดแล้วนั้น แต่คำขอจริงกลับถูกส่งไปด้วยพาธดั้งเดิมที่ยังไม่ผ่านการประมวลผล
วิธีนี้ใช้ได้ตราบที่การถอดรหัสสำเร็จ แต่หากพาธมี percent-escape ที่รูปแบบไม่ถูกต้อง เช่น % ที่อยู่โดด ๆ ใน query string ท้ายพาธ การถอดรหัสจะล้มเหลว ในกรณีนั้นโค้ดของ 1.19.1 จะถอยกลับไปตรวจสอบสตริงดิบที่ยังเข้ารหัสอยู่ ขณะที่ API server ไม่มีการถอยกลับแบบนี้ แต่จะถอดรหัสพาธทั้งหมดและส่งคำขอต่อไปตามเส้นทาง ผลคือกลไกจำกัดเห็น namespace ของ tenant เอง ในขณะที่ API server เห็นส่วน .. ที่ถูกเข้ารหัสไว้ซึ่งไต่ออกจาก namespace นั้น ไปยัง namespace อื่นหรือไปยังคอลเลกชันระดับคลัสเตอร์
advisory เน้นว่านี่คืออินพุตทั้งกลุ่ม ไม่ใช่ payload เพียงรูปแบบเดียว การบล็อกสตริงใดสตริงหนึ่งจึงไม่สามารถปิดช่องโหว่นี้ได้ การแก้ไขที่ยั่งยืนคือการตรวจสอบและดำเนินการกับพาธเดียวกันทุกประการ
นั่นคือสิ่งที่ 1.19.2 ทำ จากการอ่านซอร์สโค้ดของ 1.19.2 ของเรา ตอนนี้ Kyverno สร้างพาธในรูปแบบมาตรฐานเพียงรูปแบบเดียว ปฏิเสธพาธที่แปลงเป็นรูปแบบมาตรฐานไม่ได้ ตรวจสอบ namespace จากรูปแบบนั้น และส่งรูปแบบเดียวกันนั้นไปยัง API server ปัญหาที่เกี่ยวข้องซึ่งแก้ไขในรุ่นเดียวกันคือ CVE-2026-122310 (GHSA-3xfv-vq8x-qhg4) ใช้ประโยชน์จากความแตกต่างเดียวกันระหว่างการตรวจสอบบนพาธที่ทำความสะอาดแล้วกับคำขอดิบ โดยซ่อนส่วน ../ ไว้หลัง # หรือ ? ปัญหานี้เป็น CVE แยกต่างหากที่มีระเบียนของตัวเอง
ลำดับขั้นการยกระดับสิทธิ์
ผู้รายงานสาธิตลำดับการโจมตีนี้บน Kubernetes 1.31 กับ Kyverno 1.19.1 ที่ติดตั้งจาก Helm chart มาตรฐานด้วยค่าเริ่มต้น
- สร้าง Policy ระดับ namespace สิทธิ์เดียวที่ tenant มีคือการสร้าง
policies.kyverno.ioใน namespace ของตนเอง policy นี้มีapiCallที่พาธผ่านการตรวจสอบของกลไกจำกัดได้ แต่ถูกส่งไปยังปลายทางอื่น - ทำให้ policy ทำงาน เพียงสร้างออบเจ็กต์ทั่วไปใด ๆ ที่ตรงกับ policy เช่น ConfigMap ใน namespace ของ tenant ก็จะทำให้ Kyverno ประเมินกฎและเรียก API ในฐานะ ServiceAccount ของ admission controller
- อ่านข้อมูลข้าม namespace เทคนิคเดียวกันนี้ใช้อ่านออบเจ็กต์ใน namespace อื่นได้ รวมถึง Secrets หาก deployment ของ Kyverno มีสิทธิ์อ่าน
- เขียน webhook ระดับทั้งคลัสเตอร์ ServiceAccount นี้สร้าง MutatingWebhookConfigurations และ ValidatingWebhookConfigurations ได้ tenant จึงลงทะเบียน webhook ของตนเองได้ ซึ่ง webhook นั้นจะดักและแก้ไขคำขอ admission ในทุก namespace
- ได้สิทธิ์ผู้ดูแลคลัสเตอร์ advisory อธิบายการใช้ webhook ดังกล่าวเพื่อแก้ไข pod ที่สร้างใน kube-system และจากจุดนั้นมอบสิทธิ์ cluster-admin ให้แก่ tenant ผลลัพธ์คือการสูญเสียการรักษาความลับ ความถูกต้องสมบูรณ์ และความพร้อมใช้งานโดยสิ้นเชิง
การโจมตีนี้ไม่ต้องอาศัยการโต้ตอบจากผู้ใช้ และ webhook จะทำงานจากกิจกรรมปกติของคลัสเตอร์
ใครได้รับผลกระทบ
ระเบียน CVE ระบุว่า Kyverno 1.19.1 ได้รับผลกระทบ และ 1.19.2 ไม่ได้รับผลกระทบ รุ่นก่อน 1.19.1 ไม่มีช่องทางบายพาสนี้โดยเฉพาะ เพราะไม่มีกลไกจำกัดเลย แต่รุ่นเหล่านั้นได้รับผลกระทบจาก advisory ก่อนหน้าที่กลไกจำกัดถูกสร้างขึ้นมาเพื่อแก้ไข การใช้รุ่นเก่าต่อไปจึงไม่ใช่ทางเลือกที่ปลอดภัย ความเสี่ยงสูงที่สุดในสภาพแวดล้อมที่อนุญาตให้เจ้าของ namespace, CI pipeline หรือพอร์ทัลบริการตนเองสร้าง Kyverno Policy ได้
Kyverno 1.19.2 ออกเมื่อวันที่ 20 ตุลาคม 2026 และ release notes ระบุ GitHub security advisory ไว้ 24 รายการ: ระดับวิกฤต 9 รายการ ระดับสูง 14 รายการ และระดับปานกลาง 1 รายการ หลายรายการเกี่ยวข้องกับการตรวจสอบพาธ API และการจำกัดขอบเขต namespace advisory นี้เผยแพร่หลังจากนั้นสามวัน คือวันที่ 23 ตุลาคม แต่ทั้ง advisory และระเบียน CVE ระบุว่า 1.19.2 เป็นรุ่นที่แก้ไขแล้ว แต่ละ advisory มีรหัสของตัวเอง จึงควรจับคู่ทีละรายการ แทนที่จะมองทั้งชุดเป็น CVE เดียว
สิ่งที่ควรตรวจสอบในคลัสเตอร์ของคุณ
ขั้นแรก ให้หาเวอร์ชัน Kyverno ที่ทำงานอยู่จริง ไม่ใช่เวอร์ชันที่อยู่ใน Git repository ของคุณ:
kubectl get deployments -n kyverno -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}'
หาก image tag ใดเป็น v1.19.1 ให้วางแผนอัปเกรดเป็น 1.19.2 ทันที จากนั้นตรวจสอบสี่เรื่องต่อไปนี้:
- ใครสร้าง Policy ระดับ namespace ได้บ้าง ทดสอบด้วยตัวตนของ tenant โดยตรง และมองหา role ที่ให้สิทธิ์
policies.kyverno.ioรวมถึง ClusterRole แบบ aggregated ที่เพิ่มสิทธิ์ให้กับ role admin และ edit ที่มีมาในตัว - policy ที่มีอยู่ซึ่งใช้ apiCall แสดงรายการและตรวจทานทุก
urlPathโดยเฉพาะพาธที่มี%,..,?หรือ# - การกำหนดค่า webhook เปรียบเทียบรายการกับสิ่งที่คุณคาดไว้ Kyverno สร้าง webhook ของตัวเองอยู่แล้ว จึงควรเน้นชื่อที่คุณไม่รู้จักและเวลาสร้างที่เพิ่งเกิดขึ้น
- Audit log มองหาคำขอจาก ServiceAccount ของ admission controller ของ Kyverno ที่สร้างการกำหนดค่า webhook หรืออ่าน Secrets ผิดไปจากรูปแบบปกติ
kubectl auth can-i create policies.kyverno.io -n team-a --as=system:serviceaccount:team-a:default
kubectl get policies.kyverno.io -A -o json | jq -r '.items[] | select([.spec.rules[]?.context[]? | select(.apiCall)] | length > 0) | "\(.metadata.namespace)/\(.metadata.name)"'
kubectl get mutatingwebhookconfigurations,validatingwebhookconfigurations -o custom-columns=NAME:.metadata.name,CREATED:.metadata.creationTimestamp
แทนที่ team-a ด้วย namespace และตัวตนของ tenant ของคุณเอง หากพบ webhook ที่อธิบายไม่ได้บนคลัสเตอร์ที่เคยรัน 1.19.1 ให้ถือว่าอาจเป็นเหตุการณ์ด้านความปลอดภัย: เก็บรักษา audit log ไว้ก่อนลบสิ่งใด
บทเรียนที่กว้างกว่า: ตรวจสอบตัวผู้บังคับใช้เอง
Admission controller, policy engine และ operator มักเป็นคอมโพเนนต์ที่มีสิทธิ์สูงที่สุดในคลัสเตอร์ คอมโพเนนต์เหล่านี้ต้องการสิทธิ์กว้างขวางเพื่อทำงาน และ tenant ก็โต้ตอบกับมันทุกวัน จึงเป็นเป้าหมายที่น่าดึงดูด ในกรณีนี้ โมเดล multi-tenancy พึ่งพาการตรวจสอบเพียงจุดเดียว และขั้นตอนการถอดรหัสเพียงขั้นตอนเดียวที่การตรวจสอบกับคำขอจัดการต่างกันก็เพียงพอที่จะทำลายมันได้
สำหรับแพลตฟอร์ม Kubernetes แบบ private cloud และ multi-tenant มีสามแนวปฏิบัติที่ช่วยได้ ให้ถือว่า policy engine เป็นส่วนหนึ่งของพื้นผิวการโจมตี และติดตามรุ่นแก้ไขด้านความปลอดภัยอย่างใกล้ชิดเช่นเดียวกับเวอร์ชันของ Kubernetes ให้สิทธิ์แก่ ServiceAccount ของคอมโพเนนต์เหล่านี้เท่าที่จำเป็น เช่น ไม่ให้สิทธิ์อ่าน Secret เว้นแต่มี policy ที่ต้องใช้ และทบทวนว่า tenant เข้าถึงฟีเจอร์ใดได้บ้างผ่านการมอบสิทธิ์ เพราะฟีเจอร์ที่ทำงานด้วยสิทธิ์ของแพลตฟอร์มจะเปลี่ยนอินพุตของ tenant ให้กลายเป็นการกระทำของแพลตฟอร์ม
แหล่งข้อมูล
- Kyverno security advisory GHSA-39w8-hv5g-f73w: การยกระดับสิทธิ์เป็น cluster-admin ผ่านการบายพาสกลไกจำกัด namespace ของ apiCall ใน v1.19.1 ด้วย percent-escape ที่รูปแบบไม่ถูกต้อง
- ระเบียน CVE: CVE-2026-124440
- VulnCheck advisory: การยกระดับสิทธิ์ใน Kyverno 1.19.1 ผ่านการบายพาสกลไกจำกัด namespace ของ apiCall
- การแก้ไขที่เกี่ยวข้องในรุ่นเดียวกัน CVE-2026-122310: VulnCheck advisory และ GHSA-3xfv-vq8x-qhg4
- Release notes ของ Kyverno v1.19.2: github.com/kyverno/kyverno/releases/tag/v1.19.2
Global
Japan
Korea
China
Taiwan
Vietnam
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia