Skip to content

Unauthenticated Runner API Allows Triggering Arbitrary Playbook Actions, Including Destructive Kubernetes Operations #2174

Description

@carfeii

Affected versions: confirmed against the current default branch as of 2026-09-16

Summary

The runner's HTTP API (src/robusta/runner/web.py) has no authentication on any endpoint. POST /api/trigger accepts a caller-chosen action_name and action_params and dispatches them directly to the playbook execution engine, with no credential check. Robusta ships built-in actions that perform destructive Kubernetes operations, including drain (evicts every pod from a node) and rollout_restart (forces a deployment restart). The runner binds to 0.0.0.0 by default.

Details

@staticmethod
@app.route("/api/trigger", methods=["POST"])
def handle_manual_trigger():
    data = request.get_json()
    ...
    return jsonify(
        Web.event_handler.run_external_action(
            action_name=data["action_name"],
            action_params=data.get("action_params", None),
            sinks=data.get("sinks", None),
            sync_response=data.get("sync_response", False),
            no_sinks=data.get("no_sinks", False),
        )
    )

action_name is resolved against the full playbook action registry with no allowlist for this endpoint. Built-in actions include:

# playbooks/robusta_playbooks/node_actions.py
@action
def drain(event: NodeEvent):
    ...

# playbooks/robusta_playbooks/workload_actions.py
@action
def rollout_restart(event: KubernetesResourceEvent):
    ...

The same lack of authentication applies to the sibling endpoints /api/alerts (the Alertmanager webhook receiver, which also drives automatic remediation), /api/handle, /api/helm-releases, and /api/playbooks/reload. env_vars.py confirms the default bind address is 0.0.0.0, and there is no existing token, HMAC-signature, or secret-management infrastructure anywhere in the runner codebase for these routes.

POC

(available upon request)

Impact

Anyone who can reach the runner's HTTP port can trigger any registered playbook action, including destructive Kubernetes operations, with no authentication. Whether this is reachable from the public internet depends on the Service/Ingress configuration chosen for a given deployment, but even where the Service is ClusterIP-only, this remains a serious issue within the cluster's own network: any other workload in the same cluster (a compromised pod, a misconfigured NetworkPolicy, a pod-to-pod SSRF from an unrelated application) can reach this endpoint and trigger cluster-wide remediation actions with the Robusta service account's own RBAC permissions.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions