Back to skill

Security audit

huawei-cloud-cce-metric-analyzer

Security checks across malware telemetry and agentic risk

Overview

The skill is mostly a disclosed read-only monitoring tool, but it needs review because it can obtain Kubernetes access material and read TLS Secret objects while handling cloud credentials.

Install only if you are comfortable granting read-only Huawei Cloud and Kubernetes permissions that include cluster access setup, Pod/Service/Ingress reads, and get access to TLS Secrets. Use a dedicated least-privilege IAM user and Kubernetes RBAC role, avoid production-wide credentials, consider setting check_certificates=false unless certificate checks are needed, and verify the kubectl-cce plugin before installing it.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (38)

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill documentation describes execution through Python, local shell, networked cloud/API access, environment-variable credential fallback, and kubectl usage, but there is no explicit permission declaration constraining those capabilities. That creates a governance gap: an agent may invoke shell, network, and env-backed credential access without transparent least-privilege boundaries or user approval semantics.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill is presented primarily as a metric-analysis tool, but the documented behavior expands into direct Kubernetes API reads via kubectl, ingress/service discovery, TLS secret inspection, helper enumeration of clusters/nodes, and GPU/xGPU queries outside the stated scope. This mismatch is dangerous because users and policy engines may approve it as low-risk observability tooling while it actually accesses broader infrastructure metadata and sensitive Kubernetes objects.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill is described as a metric-analysis capability, but this file exposes broad Kubernetes inventory access for services, pods, ingresses, and secrets. That scope expansion violates least privilege and creates an unnecessary path to enumerate sensitive cluster state unrelated to metrics, making misuse or prompt-driven abuse more likely.

Context-Inappropriate Capability

Critical
Confidence
100% confidence
Finding
get_cce_secret_with_kubectl retrieves full Kubernetes Secret objects, which commonly contain credentials, tokens, certificates, and other sensitive material. For a metric-analysis skill, this is an unjustified high-risk capability that could directly expose cluster and application secrets if invoked by an attacker or through agent misuse.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The function `list_eip_addresses` performs cloud resource inventory, returning EIP identifiers, public IP addresses, instance associations, and project metadata. That behavior exceeds the declared metric-analysis scope of the skill, which increases the blast radius from read-only monitoring to infrastructure enumeration and can expose sensitive environment topology that may aid follow-on attacks or unauthorized reconnaissance.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The function `list_nat_gateways` allows enumeration of NAT gateways and returns raw gateway objects, which is broader than the skill's advertised purpose of analyzing metrics. In a monitoring skill, this kind of infrastructure discovery is dangerous because it reveals network architecture and resource details that can be abused for reconnaissance, especially when users may invoke the skill expecting only scoped metric retrieval.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
access_key = ak or os.environ.get("HUAWEI_AK") or os.environ.get("HUAWEICLOUD_SDK_AK") or os.environ.get("HW_ACCESS_KEY")
    secret_key = sk or os.environ.get("HUAWEI_SK") or os.environ.get("HUAWEICLOUD_SDK_SK") or os.environ.get("HW_SECRET_KEY")
    proj_id = project_id or os.environ.get("HUAWEI_PROJECT_ID") or os.environ.get("HUAWEICLOUD_SDK_PROJECT_ID") or os.environ.get("HW_PROJECT_ID")
    env = os.environ.copy()
    env["CCE_CLUSTER_ID"] = cluster_id
    env["CCE_REGION"] = region
    env["HW_REGION"] = region
Confidence
84% confidence
Finding
Copying the entire process environment into the child kubectl process forwards all ambient secrets and unrelated environment state to an external executable/plugin. That unnecessarily broadens secret exposure and increases the blast radius if kubectl, a plugin, or a diagnostic path leaks environment variables.

Credential Access

High
Category
Privilege Escalation
Content
It also includes CoreDNS, nginx-ingress, and autoscaler summaries. Cloud resources are scoped to the current cluster when an association can be proven: ELB is matched through LoadBalancer Service IP/EIP, NAT Gateway is filtered by the cluster VPC, and EIP is limited to associated ELB/NAT/Service IPs.

LoadBalancer Service discovery uses `kubectl` with generated kubeconfig through the cluster EIP when external access is available. If the cluster has no EIP, it uses the `kubectl cce` plugin. If neither path works, aggregation fails.

## Risk Levels
Confidence
89% confidence
Finding
The skill explicitly supports generated kubeconfig use and kubectl access paths to the cluster, which constitute credential/material access to Kubernetes. Even if intended as read-only, kubeconfig and related auth material can expose cluster API access and, combined with secret reads for TLS inspection, substantially increase the blast radius if mishandled, logged, or reused.

Credential Access

High
Category
Privilege Escalation
Content
return {"success": True, "cluster": result.get("data") or {}}


def _create_kubeconfig(region: str, cluster_id: str, ak: Optional[str], sk: Optional[str], project_id: Optional[str]) -> Dict[str, Any]:
    result = run_hcloud(
        "CCE",
        "CreateKubernetesClusterCert",
Confidence
96% confidence
Finding
This code path requests a Kubernetes cluster certificate/kubeconfig from the cloud API, enabling direct authenticated access to cluster resources. In a metric-analysis skill, generating cluster access material is broader than necessary and materially increases the impact of misuse.

Credential Access

High
Category
Privilege Escalation
Content
)
    if not result.get("success"):
        return result
    kubeconfig = result.get("data") or {}
    if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
Confidence
95% confidence
Finding
Processing the returned kubeconfig means the skill handles cluster access credentials, which can be used for broad Kubernetes API access depending on RBAC. Because this skill is meant for metrics, handling kubeconfigs is an unnecessary credential-access capability.

Credential Access

High
Category
Privilege Escalation
Content
if not result.get("success"):
        return result
    kubeconfig = result.get("data") or {}
    if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
    return {"success": True, "kubeconfig": kubeconfig}
Confidence
95% confidence
Finding
The existence check confirms the code expects and consumes usable kubeconfig credential material. This is dangerous in context because the skill's mission does not justify acquiring generalized cluster credentials.

Credential Access

High
Category
Privilege Escalation
Content
return result
    kubeconfig = result.get("data") or {}
    if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
    return {"success": True, "kubeconfig": kubeconfig}
Confidence
95% confidence
Finding
Mutating the kubeconfig to select a context further operationalizes the credential for cluster access. That turns the skill into a general Kubernetes access mechanism rather than a metric-only analyzer.

Credential Access

High
Category
Privilege Escalation
Content
kubeconfig = result.get("data") or {}
    if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
    return {"success": True, "kubeconfig": kubeconfig}
Confidence
95% confidence
Finding
Returning the kubeconfig object internally preserves and passes around active cluster credentials, increasing the chance of accidental leakage or misuse by downstream code. This exceeds the principle of least privilege for the declared use case.

Credential Access

High
Category
Privilege Escalation
Content
if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
    return {"success": True, "kubeconfig": kubeconfig}


def _prefer_external_context(kubeconfig: Dict[str, Any]) -> None:
Confidence
95% confidence
Finding
This helper is explicitly dedicated to kubeconfig context selection, reinforcing that the skill is designed to operationalize cluster credentials. In a metric-analysis context, that capability is unnecessarily powerful and broad.

Credential Access

High
Category
Privilege Escalation
Content
if not kubeconfig.get("clusters"):
        return {"success": False, "error": "CreateKubernetesClusterCert returned no kubeconfig clusters"}
    _prefer_external_context(kubeconfig)
    return {"success": True, "kubeconfig": kubeconfig}


def _prefer_external_context(kubeconfig: Dict[str, Any]) -> None:
Confidence
95% confidence
Finding
This helper is explicitly dedicated to kubeconfig context selection, reinforcing that the skill is designed to operationalize cluster credentials. In a metric-analysis context, that capability is unnecessarily powerful and broad.

Credential Access

High
Category
Privilege Escalation
Content
return {"success": True, "kubeconfig": kubeconfig}


def _prefer_external_context(kubeconfig: Dict[str, Any]) -> None:
    external_cluster_name = None
    for cluster in kubeconfig.get("clusters", []) or []:
        name = cluster.get("name", "")
Confidence
94% confidence
Finding
Iterating over kubeconfig clusters indicates the skill inspects and uses credential-bearing configuration data for endpoint selection. That is an elevated credential-access pattern not needed for pure metrics retrieval.

Credential Access

High
Category
Privilege Escalation
Content
def _prefer_external_context(kubeconfig: Dict[str, Any]) -> None:
    external_cluster_name = None
    for cluster in kubeconfig.get("clusters", []) or []:
        name = cluster.get("name", "")
        if "external" in name and "TLS" not in name:
            external_cluster_name = name
Confidence
94% confidence
Finding
Selecting an external cluster entry intentionally prefers network-reachable access, which broadens exposure and facilitates direct cluster interaction over external endpoints. That increases the security risk compared with a bounded internal monitoring integration.

Credential Access

High
Category
Privilege Escalation
Content
break
    if not external_cluster_name:
        return
    for context in kubeconfig.get("contexts", []) or []:
        context_data = context.get("context") or {}
        if context_data.get("cluster") == external_cluster_name:
            kubeconfig["current-context"] = context.get("name")
Confidence
94% confidence
Finding
Iterating kubeconfig contexts is part of preparing active credential use. The danger here is the unnecessary conversion of cloud credentials into effective Kubernetes API access within a skill that should not need it.

Credential Access

High
Category
Privilege Escalation
Content
for context in kubeconfig.get("contexts", []) or []:
        context_data = context.get("context") or {}
        if context_data.get("cluster") == external_cluster_name:
            kubeconfig["current-context"] = context.get("name")
            return
Confidence
94% confidence
Finding
Assigning current-context activates the chosen kubeconfig target for subsequent kubectl commands. This is a clear step in turning retrieved credentials into live access, which is excessive for metric analysis and amplifies misuse risk.

Credential Access

High
Category
Privilege Escalation
Content
return


def _kubectl_get_with_kubeconfig(region: str, cluster_id: str, resource_args: List[str], ak: Optional[str], sk: Optional[str], project_id: Optional[str]) -> Dict[str, Any]:
    cluster_result = _show_cluster(region, cluster_id, ak, sk, project_id)
    if not cluster_result.get("success"):
        return cluster_result
Confidence
95% confidence
Finding
This function orchestrates cluster inspection and kubeconfig-based kubectl access, effectively acting as a general cluster access helper. That capability is over-privileged relative to the skill's declared monitoring purpose.

Credential Access

High
Category
Privilege Escalation
Content
if not _cluster_has_external_access(cluster_result.get("cluster") or {}):
        return {"success": False, "error": "cluster has no bound EIP/external endpoint"}

    kubeconfig_result = _create_kubeconfig(region, cluster_id, ak, sk, project_id)
    if not kubeconfig_result.get("success"):
        return kubeconfig_result
Confidence
96% confidence
Finding
Calling _create_kubeconfig here triggers issuance of fresh cluster access material when an external endpoint is present. This directly expands the skill from metrics analysis into credentialed cluster access, increasing attack surface and potential impact.

Credential Access

High
Category
Privilege Escalation
Content
if not _cluster_has_external_access(cluster_result.get("cluster") or {}):
        return {"success": False, "error": "cluster has no bound EIP/external endpoint"}

    kubeconfig_result = _create_kubeconfig(region, cluster_id, ak, sk, project_id)
    if not kubeconfig_result.get("success"):
        return kubeconfig_result
Confidence
96% confidence
Finding
Calling _create_kubeconfig here triggers issuance of fresh cluster access material when an external endpoint is present. This directly expands the skill from metrics analysis into credentialed cluster access, increasing attack surface and potential impact.

Credential Access

High
Category
Privilege Escalation
Content
return {"success": False, "error": "cluster has no bound EIP/external endpoint"}

    kubeconfig_result = _create_kubeconfig(region, cluster_id, ak, sk, project_id)
    if not kubeconfig_result.get("success"):
        return kubeconfig_result

    kubeconfig_file = None
Confidence
95% confidence
Finding
The code flow handles kubeconfig results as a normal access mechanism, not an exceptional admin path. That normalizes credential acquisition in a context where it is not justified and raises the chance of abuse.

Credential Access

High
Category
Privilege Escalation
Content
kubeconfig_result = _create_kubeconfig(region, cluster_id, ak, sk, project_id)
    if not kubeconfig_result.get("success"):
        return kubeconfig_result

    kubeconfig_file = None
    try:
Confidence
93% confidence
Finding
Preparing a temporary kubeconfig file creates an additional credential-bearing artifact on disk. Even though cleanup is attempted, temporary files increase exposure to race conditions, forensic recovery, or access by other local processes.

Credential Access

High
Category
Privilege Escalation
Content
if not kubeconfig_result.get("success"):
        return kubeconfig_result

    kubeconfig_file = None
    try:
        with tempfile.NamedTemporaryFile("w", delete=False, suffix=".json") as handle:
            json.dump(kubeconfig_result["kubeconfig"], handle)
Confidence
97% confidence
Finding
Writing the kubeconfig JSON to a temporary file materializes cluster credentials on disk for use by kubectl. This is sensitive credential handling and is especially risky because the skill does not need broad Kubernetes credentials to perform metric analysis.

VirusTotal

VirusTotal findings are pending for this skill version.

View on VirusTotal

Static analysis

No suspicious patterns detected.