Back to skill

Security audit

观远BI Skill

Security checks for vulnerabilities and agentic risk

Overview

This Guandata BI skill is mostly purpose-aligned, but it has real review concerns around plaintext BI credentials, automatic local caching of business data, unvalidated cache paths, and an unsafe repeated publish bug.

Install only if you are comfortable giving the skill a Guandata BI account that can read business data and modify cards/pages. Use a least-privileged dedicated account, protect or avoid config.json password storage, review local cache retention, avoid untrusted --task and dataset ID values, and fix the version 7 release_page recursion before using page publishing.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/guandata.py:254
Finding

Cache Path Traversal Through Unvalidated Task and Dataset Identifiers

Content
View full analysis
str: if cls._task_id: return os.path.join( cls.SKILL_ROOT, '.cache', 'tasks', cls._task_id, subdir, ) return os.path.join(cls.SKILL_ROOT, '.cache', subdir) ``` The resulting path is used directly for file creation: ```python def _save_to_cache(self, data: Any, prefix: str = "data") -> str: self._ensure_data_cache_dir() ts = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] filename = f"{prefix}_{ts}.json" path = os.path.join(self.DATA_CACHE_DIR, filename) with open(path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) return path ``` Dataset identifiers are also used directly as filenames: ```python path = os.path.join(self.COLUMNS_CACHE_DIR, f"{ds_id}.json") ``` The task value is accepted without validation: ```python parser.add_argument( '--task', help='Task name used to isolate caches for different tasks', ) if args.task: GuandataClient.set_task(args.task) ``` ### Technical Analysis The `--task` argument is inserted directly into a filesystem path. The implementation does not reject absolute paths, path separators, or parent-directory components such as `..`. It also does not resolve the resulting path and verify that it remains under the intended `.cache/tasks` directory. Consequently, a task identifier such as `../../../../target` can cause cache files containing BI query results to be written outside the Skill cache. An absolute path can similarly replace the intended path prefix under standard `os.path.join()` behav ...[truncated 1580 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
config.json:3
Finding

Reusable BI Credentials Stored in Plaintext Configuration

Content
View full analysis
Dict[str, str]: config_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), '..', 'config.json', ) try: with open(config_path) as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {} _CFG = _load_config() DEFAULT_LOGIN_ID = _CFG.get("login_id", "") DEFAULT_PASSWORD = _CFG.get("password", "") ``` The client retains the reusable password for automatic reauthentication: ```python self._login_id = self.DEFAULT_LOGIN_ID self._login_password = self.DEFAULT_PASSWORD ``` ### Technical Analysis The shipped configuration contains placeholders rather than live credentials. However, the documented deployment procedure requires users to replace them with a real reusable BI username and password in the same plaintext file. Any local process or user able to read the Skill directory can recover the credentials. The file may also be exposed through backups, support bundles, repository commits, shared workspaces, or overly broad filesystem permissions. Base64 encoding during login does not mitigate storage exposure and is not encryption. The audit found that the encoded password is sent to the configured BI login endpoint and is not printed to standard output; therefore, the Base64 operation is not itself a covert exfiltration channel. ### Attack Path 1. A user places valid BI credentials in `config.json` as instructed. 2. The file is left w ...[truncated 793 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
SKILL.md:15
Finding

Persistent Agent-State Poisoning Through Mandatory Mutable Guidance

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/guandata.py:946
Finding

Infinite Recursive Page Publication in Guandata Version 7 Mode

Content
View full analysis
Dict[str, Any]: if not await self._ensure_token(): return {"error": "Token invalid; automatic login failed"} async with httpx.AsyncClient(timeout=self.DEFAULT_TIMEOUT) as client: response = await client.post( f"{self.base_url}/api/page/{pg_id}/release", json={}, headers=self._get_headers(), ) response.raise_for_status() version = _CFG.get("version", "6") if version == "7": await self.release_page(pg_id) return response.json() ``` ### Technical Analysis When the configured version is `7`, `release_page()` invokes itself after every successful release request. There is no termination condition. Each recursive invocation performs another authenticated HTTP POST before recursing again. The operation continues until a request fails, a timeout occurs, or Python raises a recursion-depth exception. The same method is reached by the manual `release-page` command and by version 7 card-saving workflows. ### Attack Path 1. The Skill is configured with `"version": "7"`. 2. A user or Agent invokes `release-page`, or a card-saving operation automatically calls `release_page()`. 3. The first authenticated release request succeeds. 4. The version check invokes `release_page()` again with the same page ID. 5. The cycle repeats, generating authenticated requests. 6. Execution terminates only after server failure, timeout, resource exhaustion, or recursion-depth exhaustion. ### Impact Assessment The defect can cause: - Local denial of service for the active Skill process. - Repeated publication attempts against the same BI page. - Unnecessary load on the BI server. - Rate-limit consump ...[truncated 301 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
SKILL.md:47
Finding

Unpinned Runtime Installation of Third-Party HTTP Dependency

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 1)May include surrounding context.

md
---
name: guandata
description: 使用观远BI来进行数据获取与数据分析。触发词:查数据、做图表、看报表、营业额、门店、会员、订单,分析
---

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
96% confidence
Finding

The skill explicitly includes rm -rf skills/guandata/.cache/*, a destructive command that can be executed with no confirmation and broad wildcard expansion. In a tool-using agent environment, such examples are dangerous because path assumptions, symlink abuse, or operator mistakes can turn cache cleanup into unintended deletion of larger portions of the workspace or evidence required for investigation.

Content

Scanner excerpt · SKILL.md (reported line 179)May include surrounding context.

md
find skills/guandata/.cache/data -name "*.csv" -mtime +7 -delete

# 清理所有缓存(彻底清空)
rm -rf skills/guandata/.cache/*

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

release_page() makes a POST to publish the page and then, when version == "7", immediately calls await self.release_page(pg_id) again with no termination condition. This creates unbounded recursion and repeated publish requests, leading to denial of service, stack exhaustion, or API abuse against the BI service whenever the method is invoked in that configuration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill metadata and all user-facing instructions are written as mandatory Chinese guidance, with no indication that users may choose another language or that the skill is intentionally restricted to Chinese-speaking contexts. This creates a locale/language policy concern because the skill effectively imposes a specific language without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documented cache-clearing commands include irreversible deletion operations, including a recursive wipe of the entire cache tree, without strong safety guidance, confirmation steps, or scope validation. In an agent skill context, operational instructions can be copied or automated, so destructive shell examples increase the chance of accidental data loss or deletion of task artifacts needed for auditing and recovery.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

User-facing docstrings, help text, status messages, and errors throughout the file are written in Chinese, and the CLI does not provide any language-selection or locale opt-in mechanism. This is a natural-language policy concern when a skill imposes a specific language on all users without documented justification or user choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

get_dataset_data() can save returned dataset contents to a local CSV file, including potentially sensitive business data and query metadata, without any built-in warning, encryption, or restrictive file handling. In a data-access skill, silent persistence increases the chance of confidential data being left on disk, copied by other users/processes, or retained longer than intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The query command always writes returned query data to a local cache CSV via _save_to_cache_csv(...), even when the user did not request --save. That means sensitive records retrieved from the BI platform are persisted to disk by default, which can violate user expectations and increase exposure on shared hosts or agent environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

cmd_get_card_data() saves normalized card data to a local CSV cache automatically, regardless of whether the user only wanted to inspect results transiently. Because card contents may include sensitive analytics data, silently persisting them on disk broadens the confidentiality risk beyond the remote BI session.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The create-and-fetch workflow writes retrieved card results to local CSV cache as part of normal execution, without a separate consent step or prominent disclosure. In an automation or shared-agent context, this can leave generated reports and underlying sensitive values accessible on disk after the task completes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module docstring at L003 is written in Chinese, and the rest of the file continues this pattern in docstrings/comments. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless a locale constraint is justified, which is not documented here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This file contains natural-language user-facing documentation exclusively in Chinese, including the module description and function docstring. Under the policy, forcing a specific language without user opt-in or clear justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code file contains user-facing natural-language docstrings and comments entirely in Chinese, such as the module description and enum class descriptions. Under the stated policy, forcing a specific language without user opt-in or a documented region-specific justification is a locale/language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring uses Chinese-only descriptive text ("ZoneData 核心生成器"), and the rest of the file continues with Chinese-only comments and user-facing strings, with no indication that the skill is region-specific or that users may choose another language. Under the policy, forced language or locale without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.