Back to skill

Security audit

grafana-inspector

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly performs Grafana API inspection, but one bundled script disables TLS certificate checks while using Grafana credentials and the documentation overstates screenshot/reporting features.

Review before installing. Use a read-only, narrowly scoped Grafana token, avoid username/password credentials when possible, do not run against sensitive production Grafana instances unless reports are stored in a protected location, and fix or avoid scripts/inspection_report.py until TLS verification is enabled. Expect API-based reports, not actual browser screenshots or Feishu document generation.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/inspection_report.py:66
Finding

TLS Certificate Verification Disabled for Authenticated Grafana Requests

Content
View full analysis

Vulnerability Details

File Location: scripts/inspection_report.py:66-73 and scripts/inspection_report.py:113-120
Vulnerability Type: Improper Certificate Validation (CWE-295)
Risk Level: High

Vulnerable Code

Dashboard discovery:

python
response = requests.get(
    search_url,
    headers=self.get_auth_headers(),
    params=params,
    auth=(self.username, self.password) if self.username and self.password else None,
    timeout=30,
    verify=False
)

Dashboard detail retrieval:

python
response = requests.get(
    url,
    headers=self.get_auth_headers(),
    auth=(self.username, self.password) if self.username and self.password else None,
    timeout=30,
    verify=False
)

Technical Analysis

The verify=False argument disables TLS certificate and hostname verification for the two Grafana API request paths. Both requests can contain sensitive authentication material:

  • A bearer API key added by get_auth_headers().
  • A username and password supplied through HTTP Basic Authentication.

Although HTTPS may still encrypt the connection, disabling certificate verification prevents the client from confirming that it is communicating with the intended Grafana server. A network-positioned attacker can present an arbitrary certificate, impersonate Grafana, and terminate the TLS connection without rejection by the client.

This flaw affects dashboard discovery and dashboard-detail retrieval. Responses from an impersonated endpoint are also trusted as inspection input, allowing an attacker to manipulate generated reports in addition to capturing credentials.

Attack Path

  1. A user configures the Skill with an HTTPS Grafana URL and a bearer API key or username/password credentials.
  2. An attacker gains a network interception position or influences DNS, routing, proxy settings, or the configured Grafana endpoint.
  3. The attacker presents a certificate that is self-signed, issued for another hostname, or otherwise untrust ...[truncated 1106 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove verify=False from both requests.get() calls so that Requests performs certificate and hostname validation using the operating system's trusted CA store:
python
response = requests.get(
    search_url,
    headers=self.get_auth_headers(),
    params=params,
    auth=(self.username, self.password) if self.username and self.password else None,
    timeout=30
)
  1. For Grafana deployments using a private certificate authority, support an explicit CA-bundle configuration rather than disabling verification:
python
ca_bundle = self.config.get("ca_bundle", True)

response = requests.get(
    search_url,
    headers=self.get_auth_headers(),
    params=params,
    auth=(self.username, self.password) if self.username and self.password else None,
    timeout=30,
    verify=ca_bundle
)
  1. Apply the same verified TLS policy consistently to dashboard discovery, dashboard-detail retrieval, and every future authenticated HTTP request.

  2. Validate configuration at startup. Reject insecure or invalid CA-bundle paths and warn when credentials are used with a plaintext http:// Grafana URL.

  3. Prefer narrowly scoped, read-only Grafana service-account tokens over reusable usernames and passwords. Rotate any credentials that may previously have traversed an unverified connection.

  4. Add automated tests confirming that self-signed, expired, and hostname-mismatched certificates are rejected unless an explicitly configured trusted CA validates them.

Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The primary purpose broadly matches Grafana inspection, including automatic dashboard discovery and multi-dashboard inspection. However, the description explicitly claims 'browser screenshots + API data inspection', while this code chunk contains no browser automation, screenshot capture, or rendering logic. It exclusively uses HTTP requests to Grafana APIs and generates reports from API responses. There are no unrelated dangerous capabilities or inconsistent resource accesses beyond Grafana API usage and local report file output. Therefore this is a description-behavior mismatch due to overstating a significant capability.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

整体上,这段代码的核心仍属于 Grafana 自动化巡检,且确实实现了自动发现仪表盘、批量分析和基于 API 的巡检,因此并非完全偏离声明目的。但声明中的重要能力“浏览器截图 + API 数据巡检”存在明显不符:代码只调用 Grafana HTTP API,没有 Selenium/Playwright/浏览器渲染或截图保存逻辑,也没有 24 小时与 7 天截图对比功能。相反,代码的实际输出是本地 JSON/Markdown 报告。由于截图能力是声明中的关键卖点之一,而代码未实现,属于实质性描述不准确,应判定为 mismatch。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

代码的核心行为与“Grafana 自动化巡检”总体一致,尤其吻合 API 数据巡检、多仪表盘巡检(通过 dashboard_uids)以及自动发现仪表盘(auto_discover, discover_limit)这几项描述。但声明中特别提到“支持浏览器截图”,而该代码片段中没有任何浏览器驱动、页面访问、截图保存或相关调用的迹象。相反,代码仅调用 GrafanaAPIInspector 做 API 检查并输出 JSON/Markdown 报告。因此存在部分描述与实际行为不符,属于能力声明超出代码实际体现范围的 mismatch。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The file forces a specific language/locale in its user-facing natural-language content, which can violate language-choice policy when no opt-in or alternative is provided. There is no indication that the skill is region-specific or that users can choose another language.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares network, file read, and file write behavior in practice but does not declare any explicit tool scope or permission boundaries in SKILL.md. In an agent environment, missing scope metadata can cause the skill to be invoked with broader capabilities than users expect, increasing the risk of unintended data access, outbound requests, and local artifact creation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description does not warn users that it will access Grafana data over the network and store inspection outputs, potentially including sensitive dashboard metadata, to local files. In a monitoring context, dashboards and generated reports may contain operational details, internal URLs, names, or other sensitive information, so lack of disclosure increases the risk of unintentional data exposure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The OpenClaw invocation phrase 执行 Grafana 巡检 is broad and lacks gating conditions, target constraints, or confirmation requirements. In agent systems, overly generic triggers can cause accidental or context-inappropriate execution, potentially leading to unsolicited network access to Grafana and local report generation using stored credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings in the module description and command-line output are consistently fixed to Chinese, with no option for the user to select another language. This matches the language/locale policy violation category because the skill imposes a locale choice rather than offering opt-in or documenting a justified regional constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script writes Markdown and JSON reports to local disk automatically, and those reports include potentially sensitive operational metadata such as Grafana URL, dashboard identifiers, alerts, and datasource inventory. In an agent/automation context, silent file creation can leak sensitive environment information into shared workspaces, logs, artifacts, or later processing stages without explicit user consent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

模块顶部说明将该脚本描述为包含浏览器截图巡检和飞书文档报告生成,但实现中没有任何截图、浏览器自动化、时间范围对比或飞书 API 调用。实际行为是发现仪表盘、读取详情、做简单配置检查,并将报告写入本地文件。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring and all user-facing status/report strings are written exclusively in Chinese, including the generated report content and runtime messages. This imposes a specific language on users without any opt-in, selection mechanism, or justification that the skill is restricted to a Chinese-speaking or region-specific environment.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
99% confidence
Finding

Disabling TLS certificate verification allows man-in-the-middle interception and tampering of HTTPS traffic to Grafana. In this script, that can expose API keys or basic-auth credentials and permit falsified dashboard metadata to be returned, undermining both confidentiality and report integrity.

Content

Scanner excerpt · scripts/inspection_report.py (reported line 71)May include surrounding context.

python
params=params,
                auth=(self.username, self.password) if self.username and self.password else None,
                timeout=30,
                verify=False
            )

            if response.status_code == 200:

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
99% confidence
Finding

The second API call also disables TLS verification, creating the same man-in-the-middle risk for dashboard detail retrieval. Because this skill processes monitoring data and may use bearer tokens or passwords, the context increases severity: compromised transport can leak secrets and poison generated inspection reports across multiple dashboards.

Content

Scanner excerpt · scripts/inspection_report.py (reported line 121)May include surrounding context.

python
headers=self.get_auth_headers(),
                auth=(self.username, self.password) if self.username and self.password else None,
                timeout=30,
                verify=False
            )

            if response.status_code == 200:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This Python file contains natural-language strings and docstrings entirely in Chinese, including the main banner and operational messages. Under the policy rule for language/locale, forcing a specific language without user opt-in or a documented justification is a policy concern.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

run() 的文档字符串和模块说明结合起来暗示其完成完整巡检流程,但该流程实际仅包含生成巡检数据、生成 Markdown、保存本地文件。这里的“完整”与文件头部功能声明存在直接意图偏差。

Content

No source excerpt is available for this finding.