Back to skill

Security audit

K8s Debug

Security checks for vulnerabilities and agentic risk

Overview

This Kubernetes debugging skill is useful, but unsafe script behavior could expose cluster credentials or run unintended local commands.

Send this skill through Review before installing. Use it only with trusted Kubernetes contexts, avoid --insecure, do not run it with untrusted environment variables, and treat all generated diagnostic output as sensitive. The token-handling and bash -c command construction should be fixed before use in production clusters.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cluster_health.sh:81
Finding
Arbitrary Command Execution Through K8S_REQUEST_TIMEOUT in cluster_health.sh<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cluster_health.sh:7`, `scripts/cluster_health.sh:81-89`, and command construction at `scripts/cluster_health.sh:159`, `179`, and `200` **Vulnerability Type**: Shell command injection through an environment variable **Risk Level**: Critical ### Vulnerable Code ```bash REQUEST_TIMEOUT="${K8S_REQUEST_TIMEOUT:-15s}" ``` ```bash run_pipe_or_warn() { local description="$1" local cmd="$2" if ! bash -o pipefail -c "$cmd"; then warn_raw "${description} failed; continuing." CHECK_FAIL_COUNT=$((CHECK_FAIL_COUNT + 1)) return 1 fi return 0 } ``` The vulnerable function is invoked with command strings containing the environment-controlled value: ```bash run_pipe_or_warn "Cluster version" "kubectl --request-timeout=\"$REQUEST_TIMEOUT\" version --client=false 2>/dev/null || kubectl --request-timeout=\"$REQUEST_TIMEOUT\" version" ``` ```bash run_pipe_or_warn "Recent events query" "kubectl --request-timeout=\"$REQUEST_TIMEOUT\" get events --all-namespaces --sort-by='.lastTimestamp' | tail -50" ``` ```bash run_pipe_or_warn "Component readiness endpoint query" "kubectl --request-timeout=\"$REQUEST_TIMEOUT\" get --raw='/readyz?verbose' 2>/dev/null || kubectl --request-timeout=\"$REQUEST_TIMEOUT\" get --raw='/healthz?verbose' 2>/dev/null || kubectl --request-timeout=\"$REQUEST_TIMEOUT\" get componentstatuses" ``` ### Technical Analysis `K8S_REQUEST_TIMEOUT` is accepted without format validation. Its value is interpolated into a command string that is subsequently evaluated by a new shell through `bash -c`. The double quotes inserted around `$REQUEST_TIMEOUT` do not make this safe. An attacker who controls the environment can include quote characters and shell operators in the value, terminate the intended argument, and append another command. Because `bash -c` reparses the completed string as shell syntax, injected operators, redirections, substitutions, and command se ...[truncated 1580 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `bash -c` and represent commands as argument arrays. 2. Implement pipelines directly in shell functions rather than constructing executable strings. 3. Validate `K8S_REQUEST_TIMEOUT` against an explicit allowlist pattern before use, for example: ```bash REQUEST_TIMEOUT="${K8S_REQUEST_TIMEOUT:-15s}" if [[ ! "$REQUEST_TIMEOUT" =~ ^[0-9]+(ms|s|m)$ ]]; then printf 'ERROR: Invalid K8S_REQUEST_TIMEOUT.\n' >&2 exit 2 fi ``` 4. Rewrite the event query without dynamic shell evaluation: ```bash recent_events() { kubectl_cmd get events --all-namespaces --sort-by=.lastTimestamp | tail -50 } run_or_warn "Recent events query" recent_events ``` 5. For fallback operations, use ordinary functions with explicit control flow: ```bash component_health() { kubectl_cmd get --raw='/readyz?verbose' 2>/dev/null || kubectl_cmd get --raw='/healthz?verbose' 2>/dev/null || kubectl_cmd get componentstatuses } run_or_warn "Component readiness endpoint query" component_health ``` 6. Add regression tests using timeout values containing quotes, semicolons, command substitutions, whitespace, and newline characters. Verify that invalid values are rejected and no marker command is executed. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/network_debug.sh:124
Finding
Arbitrary Command Execution Through Dynamic Shell Evaluation in network_debug.sh<![CDATA[ ## Vulnerability Details **File Location**: `scripts/network_debug.sh:7`, `scripts/network_debug.sh:124-132`, and `scripts/network_debug.sh:297` **Vulnerability Type**: Shell command injection through dynamically constructed commands **Risk Level**: Critical ### Vulnerable Code ```bash REQUEST_TIMEOUT="${K8S_REQUEST_TIMEOUT:-15s}" ``` ```bash run_pipe_or_warn() { local description="$1" local cmd="$2" if ! bash -o pipefail -c "$cmd"; then record_check_failure "${description} failed; continuing." return 1 fi return 0 } ``` The affected invocation constructs a shell program from the timeout, pod name, and namespace: ```bash run_pipe_or_warn "Pod describe network details query" "kubectl --request-timeout=\"$REQUEST_TIMEOUT\" describe pod \"$POD_NAME\" -n \"$NAMESPACE\" | grep -A 20 '^IP:'" ``` ### Technical Analysis The script interpolates `REQUEST_TIMEOUT`, `POD_NAME`, and `NAMESPACE` into a string and executes that string using `bash -c`. This creates a shell-injection sink. Kubernetes naming constraints and the script's pod/namespace preflight checks make exploitation through valid pod and namespace names less practical. They do not mitigate the environment-variable path: `K8S_REQUEST_TIMEOUT` is unrestricted and is not checked by the preflight logic. A malicious timeout value can escape the surrounding quotation marks and introduce shell syntax. Even where an input is expected to conform to Kubernetes naming rules, relying on a previous external command to enforce syntax is not a safe substitute for avoiding shell-string evaluation. ### Attack Path 1. The attacker controls `K8S_REQUEST_TIMEOUT` in the execution environment. 2. The attacker supplies a value containing shell metacharacters that breaks out of the quoted `--request-timeout` argument. 3. The victim runs `network_debug.sh` against an existing, accessible pod. 4. Initial checks and most diagnostics execute normally. 5. When the script reaches the ...[truncated 816 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Delete the generic `run_pipe_or_warn` function and do not pass executable commands as strings. 2. Validate `K8S_REQUEST_TIMEOUT` using a strict duration allowlist. 3. Use direct argument passing for all pod and namespace values. 4. Replace the affected code with a function containing an explicit pipeline: ```bash pod_network_details() { kubectl_cmd describe pod "$POD_NAME" -n "$NAMESPACE" | grep -A 20 '^IP:' } run_or_warn "Pod describe network details query" pod_network_details ``` 5. Optionally validate `POD_NAME` and `NAMESPACE` locally against the relevant Kubernetes DNS naming constraints, while retaining direct argument passing. 6. Add negative tests proving that quotes, semicolons, command substitutions, newlines, and redirection operators in environment values cannot cause command execution. 7. Run a static shell analyzer such as ShellCheck in CI and prohibit `bash -c` with dynamically generated strings. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/network_debug.sh:145
Finding
Kubernetes Service-Account Token Exposed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/network_debug.sh:145-175` and `scripts/network_debug.sh:182-194` **Vulnerability Type**: Plaintext credential exposure in command-line arguments **Risk Level**: High ### Vulnerable Code ```bash read_serviceaccount_token() { local token token="$(pod_exec cat "$SERVICEACCOUNT_TOKEN_FILE" 2>/dev/null || true)" token="${token//$'\r'/}" token="${token//$'\n'/}" printf "%s" "$token" } ``` The secure probe reads the credential and inserts it into command arguments: ```bash token="$(read_serviceaccount_token)" if [ -z "$token" ]; then echo "service account token is empty; cannot authenticate secure API probe." >&2 return 1 fi if pod_exec curl --fail --silent --show-error --cacert "$SERVICEACCOUNT_CA" --max-time 5 \ -H "Authorization: Bearer $token" "$KUBERNETES_API_URL" >/dev/null 2>&1; then return 0 fi if pod_exec wget -q --timeout=5 --ca-certificate="$SERVICEACCOUNT_CA" \ --header="Authorization: Bearer $token" -O /dev/null "$KUBERNETES_API_URL" >/dev/null 2>&1; then return 0 fi ``` The insecure override repeats the exposure: ```bash token="$(read_serviceaccount_token)" warn "Insecure TLS mode enabled (--insecure). Certificate validation is bypassed for API probe." if [ -n "$token" ]; then if pod_exec curl --fail --silent --show-error -k --max-time 5 \ -H "Authorization: Bearer $token" "$KUBERNETES_API_URL" >/dev/null 2>&1; then return 0 fi if pod_exec wget -q --timeout=5 --no-check-certificate \ --header="Authorization: Bearer $token" -O /dev/null "$KUBERNETES_API_URL" >/dev/null 2>&1; then return 0 fi fi ``` ### Technical Analysis The script uses `kubectl exec` to copy a bearer token from the target pod into a local shell variable. It then embeds the token in the argument vector of the local `kubectl` process as part of the remote command. During execution, the complete authorization header may be obse ...[truncated 2250 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not read the service-account token for a connectivity test. 2. Probe the API endpoint without credentials and treat any valid HTTP response, including `401` or `403`, as proof of network and TLS connectivity. 3. If an authenticated test is strictly required, execute a purpose-built helper entirely inside the pod and prevent the token from appearing in command arguments. 4. Prefer an API client that reads the token directly from the mounted file and transmits it without placing it in the process argument vector. 5. Do not offer an authenticated `--insecure` mode. If certificate verification must be disabled for troubleshooting, perform only an unauthenticated probe. 6. Avoid storing the token in a local shell variable. 7. Document that process tracing and verbose shell debugging must remain disabled around credential-handling operations. 8. Add tests that inspect the generated `kubectl` arguments and assert that they never contain `Authorization`, `Bearer`, or token contents. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/common_issues.md:72
Finding
Registry Password Recommended as a Plaintext Command-Line Argument<![CDATA[ ## Vulnerability Details **File Location**: `references/common_issues.md:72-75` and `references/troubleshooting_workflow.md:114-118` **Vulnerability Type**: Insecure credential handling in documented operational commands **Risk Level**: Medium ### Vulnerable Code In `references/common_issues.md`: ```bash kubectl create secret docker-registry <secret-name> --docker-server=<registry> --docker-username=<user> --docker-password=<pass> ``` In `references/troubleshooting_workflow.md`: ```bash kubectl create secret docker-registry <secret> \ --docker-server=<server> \ --docker-username=<user> \ --docker-password=<pass> ``` ### Technical Analysis The documentation directs users to provide a registry password directly as a command-line argument. When users replace the placeholder with a real credential, the plaintext password may be retained in: - Interactive shell history. - Process argument listings while `kubectl` is running. - Command auditing and endpoint monitoring records. - CI/CD job definitions and logs. - Terminal transcripts or Agent execution logs. Although the examples contain placeholders rather than embedded real secrets, the prescribed workflow encourages insecure handling of production credentials. Skill documentation forms part of the operational behavior because an Agent or user may execute the suggested commands directly. ### Attack Path 1. A user follows the documented ImagePullBackOff remediation workflow. 2. The user replaces `<pass>` with an actual registry password. 3. The complete command is entered into a shell or generated by automation. 4. The credential is stored in shell history, job logs, process auditing, or command telemetry. 5. Another local user, CI administrator, log reader, or compromised monitoring component retrieves the plaintext password. 6. The attacker authenticates to the container registry. 7. Depending on registry permissions, the attacker reads private images or modifies image tags and artifacts c ...[truncated 617 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove examples that place literal passwords in command-line arguments. 2. Recommend a protected Docker configuration file or another credential-provider integration: ```bash kubectl create secret generic <secret-name> \ --from-file=.dockerconfigjson="$HOME/.docker/config.json" \ --type=kubernetes.io/dockerconfigjson ``` 3. Ensure the source credential file has restrictive permissions and is not committed to source control. 4. Where supported, prefer cloud workload identity or short-lived registry tokens over long-lived passwords. 5. If interactive password entry is unavoidable, use a non-echoing prompt and ensure the credential is not expanded into a logged command. 6. Add an explicit warning that registry credentials must not be typed directly into commands, stored in shell history, or placed in CI logs. 7. Scope registry credentials to read-only access and only the repositories required by the workload. 8. Update both affected reference files so they provide the same secure workflow. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill description understates sensitive behavior by presenting itself as broad Kubernetes diagnosis/fix guidance while also directing in-pod exec-based inspection and local file capture. That mismatch is dangerous because operators and policy engines may approve the skill for routine troubleshooting without realizing it can read in-container configuration and service-account-backed API context from workloads.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The skill description understates sensitive behavior by presenting itself as broad Kubernetes diagnosis/fix guidance while also directing in-pod exec-based inspection and local file capture. That mismatch is dangerous because operators and policy engines may approve the skill for routine troubleshooting without realizing it can read in-container configuration and service-account-backed API context from workloads.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return 1
    fi

    if pod_exec curl --fail --silent --show-error --cacert "$SERVICEACCOUNT_CA" --max-time 5 \
        -H "Authorization: Bearer $token" "$KUBERNETES_API_URL" >/dev/null 2>&1; then
        return 0
    fi
Confidence
75% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return 0
    fi

    if pod_exec wget -q --timeout=5 --ca-certificate="$SERVICEACCOUNT_CA" \
        --header="Authorization: Bearer $token" -O /dev/null "$KUBERNETES_API_URL" >/dev/null 2>&1; then
        return 0
    fi
Confidence
75% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
-H "Authorization: Bearer $token" "$KUBERNETES_API_URL" >/dev/null 2>&1; then
            return 0
        fi
        if pod_exec wget -q --timeout=5 --no-check-certificate \
            --header="Authorization: Bearer $token" -O /dev/null "$KUBERNETES_API_URL" >/dev/null 2>&1; then
            return 0
        fi
Confidence
97% confidence
Finding
This code explicitly invokes wget with --no-check-certificate in the --insecure path while also sending the pod's service account bearer token to the Kubernetes API. Disabling TLS certificate validation allows a man-in-the-middle or DNS-spoofed endpoint inside the cluster to impersonate the API server and capture that token, which can lead to unauthorized Kubernetes API access depending on the service account's RBAC.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"$KUBERNETES_API_URL" >/dev/null 2>&1; then
            return 0
        fi
        if pod_exec wget -q --timeout=5 --no-check-certificate \
            -O /dev/null "$KUBERNETES_API_URL" >/dev/null 2>&1; then
            return 0
        fi
Confidence
91% confidence
Finding
This wget call disables certificate verification with --no-check-certificate for an unauthenticated probe to the Kubernetes API. Even without the bearer token, it normalizes insecure TLS behavior and permits spoofed responses from a malicious endpoint, which can mislead diagnostics and weaken operator security practices.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
has_no_check=0
        for arg in "${exec_args[@]}"; do
            [[ "$arg" == --ca-certificate=* ]] && has_ca=1
            [[ "$arg" == "--no-check-certificate" ]] && has_no_check=1
        done

        if [[ "${K8S_STUB_EXPECT_SECURE:-0}" == "1" ]]; then
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
run_script "$NETWORK_SCRIPT" demo-pod
assert_exit "secure default run returns success" 0
assert_log_contains "secure probe passes --cacert" "--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
assert_log_not_contains "secure probe does not use -k" " exec .* -- curl .* -k "

echo ""
echo "[P0] network_debug insecure mode remains explicit"
Confidence
75% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill explicitly instructs the agent to use shell commands, environment variables, and local file writes, but it does not declare any tool scope or permission boundaries. In an agent setting this creates an authorization gap: a caller may invoke a skill that can access cluster data and write diagnostics locally without transparent, least-privilege constraints.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Execute kubectl command and return (stdout, stderr, exit_code)."""
    cmd = ["kubectl", f"--request-timeout={REQUEST_TIMEOUT}", *args]
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'cmd' from os.environ.get (line 21, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
"""Execute kubectl command and return (stdout, stderr, exit_code)."""
    cmd = ["kubectl", f"--request-timeout={REQUEST_TIMEOUT}", *args]
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script collects and can persist pod YAML, descriptions, events, node details, and container logs, all of which may contain secrets, tokens, internal hostnames, environment variables, or sensitive workload data. Writing this bundle to an arbitrary file path without a clear warning, redaction, or permission hardening increases the chance of credential disclosure or leakage of sensitive cluster metadata.

Missing User Warnings

Low
Confidence
78% confidence
Finding
This is a markdown file, so SQP-2 applies to omissions in user-facing warnings. The document includes operationally impactful actions like `kubectl rollout restart` and `kubectl rollout undo`, but it does not warn that these commands can affect availability or revert running changes, which could impact user data or system integrity during troubleshooting.

Static analysis

No suspicious patterns detected.