Prowler: Remote code execution on the workers via a kubeconfig with an auth-provider cmd-path
An account self-registered in the default configuration creates a Kubernetes provider with a kubeconfig that carries a legacy auth-provider with cmd-path, and during the connection test runs arbitrary commands on the Celery worker shared by all tenants.
Advisory ID: TP-2026-040
Product: Prowler (Open-source CSPM platform; Prowler App consists of a Django REST API, Celery workers and a Next.js UI)
Vulnerability type: OS command injection through an incomplete blocklist (CWE-78, CWE-94)
CVE: CVE-2026-73263
CVSS 3.1: 9.9 (Critical) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Vendor advisory: GHSA-ccqh-6cjc-wp4j
Affected versions: < 5.36.0
Fixed in: 5.36.0
Reported: 10 July 2026
Summary
Prowler is a cloud security posture management platform; the Prowler App manages the cloud credentials of several tenants through a Django REST API and Celery workers. When a Kubernetes provider is created the API stores a user-supplied kubeconfig as a secret, and the connection test later loads that kubeconfig through the kubernetes-python client. The validator that is meant to prevent command execution from kubeconfigs only checks for exec blocks and overlooks the legacy auth-provider with cmd-path, so that variant passes the check and is stored verbatim. On load, the client runs the command placed in cmd-path through subprocess.Popen. Because self-registration is open in the default configuration, any anonymous visitor runs arbitrary commands as the prowler user on the worker shared by all tenants in three API calls, reads its secrets and thereby compromises every tenant. turingpoint verified the chain end to end and reported it to the vendor, who fixed it in 5.36.0.
Root cause
On POST /api/v1/providers/{id}/connection the stored kubeconfig secret is loaded via config.load_kube_config_from_dict (prowler/providers/kubernetes/kubernetes_provider.py:258), and the kubernetes-python client (v32.0.1) runs the value from cmd-path in CommandTokenSource.token through subprocess.Popen before any cluster is contacted. The only barrier is the validator kubeconfig_contains_exec_auth (api/src/backend/api/v1/serializers.py:1591, called from validate_kubeconfig_content :1789), which rejects an entry solely when it contains an exec block and never inspects the legacy auth-provider (name: gcp) carrying config.cmd-path/cmd-args. The validator's own error message (:1571) states that kubeconfig command authentication is refused for security reasons, so the auth-provider path is a gap in an intended blocklist rather than accepted behavior. Self-registration is open in the default configuration (POST /api/v1/users returns a usable account and /api/v1/tokens issues a JWT without email verification), so any anonymous visitor becomes a tenant admin and reaches the sink in three API calls. The injected command runs as the prowler user (uid 1000) on the Celery worker shared by all tenants, whose process environment holds DJANGO_SECRETS_ENCRYPTION_KEY and DJANGO_TOKEN_SIGNING_KEY.
Proof of Concept
# 1) Self-register and obtain a token
POST /api/v1/users -> create account
POST /api/v1/tokens -> receive JWT
# 2) Create a Kubernetes provider, then set the kubeconfig secret with a legacy auth-provider
POST /api/v1/providers/{id}/secrets
{
"...": {
"users": [{"name": "u", "user": {"auth-provider": {"name": "gcp",
"config": {"cmd-path": "/bin/sh", "cmd-args": "-c${IFS}<command>"}}}}]
}
}
# 3) The connection test triggers loading of the kubeconfig
POST /api/v1/providers/{id}/connection
The validator lets the secret through because it contains no exec block; the connection test loads the kubeconfig, and the kubernetes-python client runs cmd-path with the whitespace-split cmd-args (hence ${IFS}) through subprocess.Popen. turingpoint confirmed the execution live through a network beacon and a file written inside the container as uid=1000(prowler) on the worker.
Impact
- Arbitrary operating-system commands as the
prowleruser (uid 1000) on the Celery worker shared by all tenants. - Read of
DJANGO_SECRETS_ENCRYPTION_KEYand thereby decryption of every tenant's stored cloud credentials. - Read of
DJANGO_TOKEN_SIGNING_KEYand thereby forgery of any user's JWT. - Reachable in the default configuration without a prior invitation, because self-registration is open.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications reviewed by the same specialists, with a penetration test from turingpoint.
