Back to skill

Security audit

Byteplan Chat

Security checks for vulnerabilities and agentic risk

Overview

This BytePlan chart skill appears purpose-aligned, but it handles BytePlan credentials with overly broad and under-validated network configuration that users should review before installing.

Install only if you trust the BytePlan endpoint and the publisher. Keep BYTEPLAN_BASE_URL pinned to the intended HTTPS BytePlan host, use least-privileged/read-only credentials if possible, avoid the --system and ../../scripts install instructions, and assume your query text plus related BytePlan analysis data will be sent to the configured remote service.

Vulnerability Patterns
  • 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
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:55
Finding

Configurable API Base URL Enables Credential Redirection

Content
View full analysis

Vulnerability Details

File Location: main.py:55-58, main.py:128-132, and main.py:201-219
Vulnerability Type: Unrestricted transmission of authentication credentials to a configurable endpoint
Risk Level: Medium

Vulnerable Code

python
BASE_URL = os.getenv("BYTEPLAN_BASE_URL", "https://uatapp.byteplan.com")
PUBLIC_KEY_URL = f"{BASE_URL}/base/util/get/publicKey"
LOGIN_URL = f"{BASE_URL}/base/login"
AI_BASE_URL = f"{BASE_URL}/ai/api/ai"
python
response = requests.get(
    PUBLIC_KEY_URL,
    headers=headers,
    timeout=10
)
python
raw_password = os.getenv("BYTEPLAN_PASSWORD", "")
encrypted_password = rsa_encrypt_password(raw_password, public_key_pem)
if not encrypted_password:
    print("Password encryption failed")
    return None

login_payload = LOGIN_PAYLOAD_TEMPLATE.copy()
login_payload["password"] = encrypted_password
login_payload["publicKeyId"] = key_id

headers = {
    "Content-Type": "application/x-www-form-urlencoded"
}

try:
    response = requests.post(
        LOGIN_URL,
        data=login_payload,
        headers=headers,
        auth=(AUTH_USER, AUTH_PASS),
        timeout=10
    )

Technical Analysis

The program permits BYTEPLAN_BASE_URL to control the destination of both the public-key request and the login request without validating that the URL belongs to an authorized BytePlan host.

RSA encryption does not protect the password from a malicious destination in this design. The public key is retrieved from the same configurable server that receives the encrypted password. An attacker controlling the configured server can return an attacker-generated public key and subsequently decrypt BYTEPLAN_PASSWORD using the corresponding private key.

The login request also transmits BYTEPLAN_AUTH_USER and BYTEPLAN_AUTH_PASS through HTTP Basic authentication. These credentials are not protected by the application-level RSA operation and are directly available to the configured HTTPS endpoint.

B ...[truncated 1991 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require HTTPS and validate the parsed URL before making any credential-bearing request.
  2. Allowlist the exact expected BytePlan hostname, such as uatapp.byteplan.com, rather than accepting arbitrary hosts.
  3. Reject URLs containing embedded credentials, unexpected ports, fragments, or non-HTTPS schemes.
  4. Maintain separate explicit allowlists for approved test and production BytePlan endpoints.
  5. Do not retrieve the password-encryption public key from an unrestricted destination. Pin an expected public-key fingerprint or validate the key through a trusted BytePlan certificate or signed key-distribution mechanism.
  6. Separate the public-key endpoint, login endpoint, and AI endpoint configuration if operational flexibility is required, and validate each endpoint independently.
  7. Warn the user and require explicit confirmation before sending credentials to any non-default approved environment.
  8. Request a read-only API scope instead of write when chart generation does not require mutation.
  9. Protect .env and deployment configuration with restrictive file permissions and prevent untrusted users from controlling inherited environment variables.
  10. Avoid logging complete error responses from authentication endpoints because they may contain sensitive diagnostic information.

T08 · Insecure Dependencies

Warning
Location
INSTALL.md:10
Finding

Unpinned Dependencies and System-Wide Installation Create Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: INSTALL.md:10-13, INSTALL.md:46-51, and SKILL.md:162-165
Vulnerability Type: Unpinned third-party dependencies installed with unnecessarily broad scope
Risk Level: Medium

Vulnerable Code

bash
uv pip install --system requests pycryptodome
bash
cd ../../scripts
yarn install
bash
uv pip install requests python-dotenv pycryptodome matplotlib numpy

Technical Analysis

The installation instructions resolve mutable package versions without a lockfile, exact version constraints, or integrity hashes. Consequently, identical installation commands may retrieve different dependency versions over time.

The --system option installs Python dependencies into the system Python environment rather than an isolated environment. This unnecessarily expands the impact of dependency compromise or incompatible upgrades to unrelated applications that use the same interpreter.

The fallback yarn install command operates in an external ../../scripts directory whose manifest and lockfile are not present in the audited artifact. The dependencies installed by that command therefore cannot be verified from this project. Although the current matplotlib implementation does not require the documented Canvas workflow, users following the stale troubleshooting instructions could still execute it.

No specific dependency in the artifact was proven malicious. The confirmed weakness is the unsafe, non-reproducible dependency installation process and its unnecessarily broad installation scope.

Attack Path

  1. A user follows the documented installation instructions.
  2. The package manager resolves the latest available versions because no exact versions or integrity hashes are specified.
  3. A dependency, transitive dependency, package release, or external ../../scripts project has been compromised or replaced.
  4. The package manager downloads the compromised component.
  5. Package build hooks, instal ...[truncated 1215 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove --system and install all dependencies into a dedicated virtual environment.
  2. Pin every direct dependency to a reviewed exact version.
  3. Generate and commit a reproducible lockfile that includes transitive dependencies.
  4. Use package hashes, such as pip hash checking, to verify downloaded artifacts.
  5. Configure trusted package indexes explicitly and require TLS.
  6. Review dependency updates before regenerating the lockfile.
  7. Add automated dependency vulnerability and provenance scanning to the release process.
  8. Remove the stale Canvas and ../../scripts Yarn instructions if the matplotlib renderer is authoritative.
  9. If Node.js dependencies remain necessary, include the relevant manifest and lockfile inside the audited project and use a deterministic command such as yarn install --frozen-lockfile.
  10. Keep installation documentation, package.json, and the actual renderer architecture synchronized so users are not directed to unaudited external components.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (32)

Tainted flow: 'PUBLIC_KEY_URL' from os.getenv (line 56, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The public-key retrieval endpoint is derived from BYTEPLAN_BASE_URL loaded from .env/environment without validation, so an attacker who can influence configuration can redirect the client to an arbitrary host. In this flow, the returned public key is then trusted for credential encryption, enabling credential capture via attacker-controlled key substitution and SSRF-style outbound requests.

Content

Scanner excerpt · main.py (reported line 128)May include surrounding context.

python
headers["referrer"] = f"{BASE_URL}/"
    
    try:
        response = requests.get(
            PUBLIC_KEY_URL,
            headers=headers,
            timeout=10

Tainted flow: 'LOGIN_URL' from os.getenv (line 57, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The login endpoint is built from environment-controlled BASE_URL and receives the username plus the password encrypted under whatever public key was previously fetched from that same untrusted origin. If the base URL is redirected to attacker infrastructure, the attacker can supply their own RSA key, decrypt the submitted password, and harvest access credentials.

Content

Scanner excerpt · main.py (reported line 217)May include surrounding context.

python
}
    
    try:
        response = requests.post(
            LOGIN_URL,
            data=login_payload,
            headers=headers,

Tainted flow: 'url' from os.getenv (line 335, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The AI identify-model request sends user-provided query data and bearer credentials to a URL derived from environment-controlled BASE_URL. If configuration is tampered with, sensitive prompts and tokens may be exfiltrated to an attacker-controlled service.

Content

Scanner excerpt · main.py (reported line 269)May include surrounding context.

python
}
    
    try:
        response = requests.post(url, headers=headers, json=payload, stream=True, timeout=60)
        
        if response.status_code != 200:
            print(f"❌ 请求失败,状态码:{response.status_code}")

Tainted flow: 'url' from os.getenv (line 335, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The analysis request transmits the user query, model metadata, and bearer token to a URL constructed from environment-controlled configuration. A malicious or compromised BASE_URL can redirect that data to an unintended external service, causing prompt/data leakage and token exposure.

Content

Scanner excerpt · main.py (reported line 357)May include surrounding context.

python
}
    
    try:
        response = requests.post(url, headers=headers, json=payload, stream=True, timeout=120)
        
        if response.status_code != 200:
            print(f"\n❌ 请求失败,状态码:{response.status_code}")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · .gitignore (reported line 2)May include surrounding context.

text
# 环境变量(包含敏感信息)
.env

# Python 虚拟环境
.venv/

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · INSTALL.md (reported line 28)May include surrounding context.

复制 .env.example 到 .env 并填写你的 BytePlan API 凭证:

bash
cp .env.example .env

状态: ✅ 已配置

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · main.py (reported line 40)May include surrounding context.

python
if sys.platform == "win32":
    sys.stdout.reconfigure(encoding="utf-8")

# 手动加载 .env 文件
script_dir = Path(__file__).parent
env_file = script_dir / ".env"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · main.py (reported line 52)May include surrounding context.

python
if sys.platform == "win32":
    sys.stdout.reconfigure(encoding="utf-8")

# 手动加载 .env 文件
script_dir = Path(__file__).parent
env_file = script_dir / ".env"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · main.py (reported line 42)May include surrounding context.

python
# 手动加载 .env 文件
script_dir = Path(__file__).parent
env_file = script_dir / ".env"

if env_file.exists():
    with open(env_file, 'r', encoding='utf-8') as f:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill documentation and usage examples are presented entirely in Chinese, and the examples imply Chinese-language queries as the expected interaction mode. Under the policy, a skill should not effectively require a specific language unless it explicitly offers language choice or clearly justifies the locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file uses Chinese throughout for headings, instructions, and release details, which effectively forces a specific language on readers. The policy for natural-language content requires either user opt-in for language/locale constraints or a clear justification that the skill is region-specific.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documentation describes capabilities that require environment-variable access, filesystem reads/writes, network access, and shell execution, but it declares no explicit tool scope or permission boundaries. In an auto-triggered skill, this creates a confused-deputy risk where the runtime may grant broader capabilities than users expect, enabling credential use, outbound API calls, and local command execution without clear least-privilege constraints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The auto-trigger description is broad enough to match many ordinary analytics or visualization requests, which can cause the skill to activate in contexts the user did not specifically intend. Because this skill performs authenticated network actions and processes potentially sensitive BytePlan data, overbroad triggering increases the chance of unintended data access or transmission.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language description, examples, and behavior are presented entirely in Chinese, and the skill emphasizes Chinese font handling and Chinese query examples without indicating that users may choose another language. Under the policy, a language constraint should either be optional for the user or explicitly justified as region-specific.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 156)May include surrounding context.

如遇到中文乱码:

bash
# Linux 安装字体
sudo apt-get install fonts-wqy-zenhei fonts-noto-cjk  # Ubuntu/Debian
sudo yum install wqy-zenhei-fonts google-noto-sans-cjk-fonts  # CentOS/RHEL

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 157)May include surrounding context.

如遇到中文乱码:

bash
# Linux 安装字体
sudo apt-get install fonts-wqy-zenhei fonts-noto-cjk  # Ubuntu/Debian
sudo yum install wqy-zenhei-fonts google-noto-sans-cjk-fonts  # CentOS/RHEL

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

如遇到中文乱码:

bash
# Linux 安装字体
sudo apt-get install fonts-wqy-zenhei fonts-noto-cjk  # Ubuntu/Debian
sudo yum install wqy-zenhei-fonts google-noto-sans-cjk-fonts  # CentOS/RHEL

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

如遇到中文乱码:

bash
# Linux 安装字体
sudo apt-get install fonts-wqy-zenhei fonts-noto-cjk  # Ubuntu/Debian
sudo yum install wqy-zenhei-fonts google-noto-sans-cjk-fonts  # CentOS/RHEL

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill silently loads credentials from .env and uses them in network authentication flows without explicit user notice or consent. In an agent-skill context, hidden credential use and remote transmission materially increase security and privacy risk because users may not realize local secrets will be sent off-host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill sends user queries and analysis payloads to external AI endpoints with no explicit warning that data leaves the local environment. In a chart-generation skill, users may input sensitive business or student data, so silent exfiltration to remote services raises meaningful confidentiality concerns.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This request transmits user query data to an external AI service. External transmission is expected for the skill's functionality, but it remains security-relevant because potentially sensitive user data is sent off-host and the destination is configuration-driven.

Content

Scanner excerpt · main.py (reported line 269)May include surrounding context.

python
}
    
    try:
        response = requests.post(url, headers=headers, json=payload, stream=True, timeout=60)
        
        if response.status_code != 200:
            print(f"❌ 请求失败,状态码:{response.status_code}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This analysis request sends user content and related metadata to a remote endpoint, which creates a genuine data-exposure risk if the content is sensitive or if endpoint configuration is altered. In this skill context, chart queries may include internal analytics data, making the transmission more consequential.

Content

Scanner excerpt · main.py (reported line 357)May include surrounding context.

python
}
    
    try:
        response = requests.post(url, headers=headers, json=payload, stream=True, timeout=120)
        
        if response.status_code != 200:
            print(f"\n❌ 请求失败,状态码:{response.status_code}")

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a BytePlan data visualization skill that generates charts, but the implementation invokes an external command (uv run python render_chart.py) instead of rendering within the current process. Spawning subprocesses is a broader execution capability that is not justified by the stated purpose of querying BytePlan data and producing charts.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · main.py (reported line 473)May include surrounding context.

python
try:
        # 使用 uv run python 运行渲染脚本(确保在虚拟环境中)
        result = subprocess.run(
            ['uv', 'run', 'python', str(render_script), antv_json_str, str(output_path)],
            capture_output=True,
            text=True,

Tainted flow: 'output_path' from os.getenv (line 463, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · main.py (reported line 473)May include surrounding context.

python
try:
        # 使用 uv run python 运行渲染脚本(确保在虚拟环境中)
        result = subprocess.run(
            ['uv', 'run', 'python', str(render_script), antv_json_str, str(output_path)],
            capture_output=True,
            text=True,

Static analysis

No suspicious patterns detected.