Back to skill

Security audit

jf-open-pro-device-battery-manage

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent JFTech battery-management helper, but it needs Review because it handles device credentials and can send signed requests or tokens to an unvalidated endpoint while printing tokens in plaintext.

Install only if you trust the publisher and execution environment, and use it with a documented JFTech endpoint only. Treat JF_UUID, JF_APP_KEY, JF_APP_SECRET, JF_DEVICE_TOKEN, and access tokens as sensitive; avoid running the token helper where console output is logged, and rotate any token that may have been printed or sent to an unexpected endpoint.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/battery_manage.py:27
Finding

Unrestricted API Endpoint Can Disclose Authentication and Device Material

Content
View full analysis

Vulnerability Details

File Locations:

  • scripts/battery_manage.py:27-28, with request sinks at 57-62, 90-95, and 113-125
  • scripts/get_device_token.py:45-70, with command-line endpoint configuration at 96
  • scripts/get_current_threshold.py:39-54, with command-line endpoint configuration at 82

Vulnerability Type: User-controlled network destination for authenticated API requests
Risk Level: High

Vulnerable Code

scripts/battery_manage.py:27-28:

python
JF_ENDPOINT = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com")
JF_BASE_URL = f"https://{JF_ENDPOINT}/gwp/v3"

scripts/battery_manage.py:57-62:

python
url = f"{JF_BASE_URL}/rtc/device/getconfig/{device_token}"
headers = get_headers(uuid, app_key, app_secret, move_card)

body = {
    "Name": "Ability.AovAbility"
}

response = requests.post(url, headers=headers, json=body, timeout=30)

scripts/get_device_token.py:45-70:

python
base_url = f"https://{endpoint}/gwp/v3"
url = f"{base_url}/rtc/device/token"
headers = get_headers(uuid, app_key, app_secret, move_card)

body = {
    "sns": [device_sn],
    "accessToken": access_token
}

print(f"请求 URL: {url}")
print(f"请求体:sns={[device_sn]}")

response = requests.post(url, headers=headers, json=body, timeout=30)
print(f"HTTP 状态码:{response.status_code}")
print(f"响应原始内容:{response.text}")

scripts/get_device_token.py:96:

python
parser.add_argument("--endpoint", default=os.getenv("JF_ENDPOINT", "api-cn.jftechws.com"), help="API 接入地址")

scripts/get_current_threshold.py:39-54:

python
base_url = f"https://{endpoint}/gwp/v3"
url = f"{base_url}/rtc/device/getconfig/{device_token}"
headers = get_headers(uuid, app_key, app_secret, move_card)

body = {
    "Name": "Dev.LowElectrMode"
}

response = requests.post(url, headers=headers, json=body, timeout=30)
result = response.json()

`scripts/g ...[truncated 2921 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace unrestricted endpoint selection with an explicit allowlist:

    python
    ALLOWED_ENDPOINTS = {
        "api-cn.jftechws.com",
        "api-as.jftechws.com",
        "api-eu.jftechws.com",
        "api-na.jftechws.com",
    }
    
    endpoint = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com").strip().lower()
    if endpoint not in ALLOWED_ENDPOINTS:
        raise ValueError("Unsupported JFTech API endpoint")
    
  2. Accept only bare hostnames. Reject values containing URL schemes, paths, query strings, fragments, credentials, ports, IP literals, or control characters.

  3. Centralize endpoint validation in one shared function and use it in all three network-enabled scripts.

  4. Do not provide unrestricted custom endpoints in production. If custom development gateways are necessary, require an explicit unsafe-development flag and display a warning before transmitting credentials.

  5. Keep TLS certificate verification enabled and do not introduce a verify=False workaround.

  6. Prefer separate, least-privileged credentials for development and production environments.

  7. Rotate device or user tokens if they may have been transmitted to an untrusted endpoint.

  8. Add automated tests confirming that undocumented domains, subdomain suffix tricks, URLs, IP addresses, and malformed endpoint values are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get_device_token.py:69
Finding

Device Token and Raw API Response Are Exposed Through Console Output

Content
View full analysis

Vulnerability Details

File Locations:

  • scripts/get_device_token.py:69-70
  • scripts/get_device_token.py:128-136

Vulnerability Type: Plaintext sensitive-data exposure through logs and terminal output
Risk Level: Medium

Vulnerable Code

scripts/get_device_token.py:69-70:

python
print(f"HTTP 状态码:{response.status_code}")
print(f"响应原始内容:{response.text}")

scripts/get_device_token.py:128-136:

python
print()
print(f"✅ 获取设备 Token 成功")
print(f"   设备:{args.device_sn}")
print(f"   Token: {token}")
print()
print(f"💡 提示:设置环境变量后使用 battery_manage.py 查询电量阈值")
print(f"   export JF_DEVICE_TOKEN=\"{token}\"")

Technical Analysis

The token-acquisition helper prints the complete HTTP response before parsing it and then prints the full device token twice. The second occurrence is embedded in a shell command.

Device tokens are bearer-style credentials used in device API URL paths. Any party able to read the output may recover the token without needing the application secret. The raw response can also expose additional sensitive fields if the API response format changes or contains diagnostic information.

Console output is not a safe secret-delivery channel. It may be retained in:

  • Terminal scrollback
  • AI agent conversation transcripts
  • CI/CD job logs
  • Centralized logging systems
  • Shell session recordings
  • Support bundles or debugging captures

Printing the device serial number alongside the token further improves an observer's ability to associate the credential with its target device.

Attack Path

  1. A user or AI agent invokes get_device_token.py with valid platform credentials and a bound device serial number.
  2. JFTech returns a valid device token.
  3. The script writes the complete raw response and full token to standard output.
  4. The output is retained by terminal history, an agent transcript, CI logging, monitoring infrastructure, or another ...[truncated 814 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove raw-response logging from normal operation:

    python
    print(f"HTTP status: {response.status_code}")
    

    Do not print response.text when the response may contain credentials.

  2. Do not print the full token or a ready-to-copy shell command containing it. Display only a confirmation or a masked representation:

    python
    masked = f"...{token[-4:]}" if token and len(token) >= 4 else "[redacted]"
    print(f"Device token obtained successfully: {masked}")
    
  3. Return the token directly to the calling process rather than routing it through logs.

  4. If persistence is required, store the token in a dedicated credential store or a file created with owner-only permissions, such as mode 0600.

  5. Make any full-token output an explicit opt-in operation, warn the user that the value is sensitive, and ensure it is written only to a designated secure output stream.

  6. Introduce structured logging with field-level redaction for keys such as token, accessToken, signature, and authorization headers.

  7. Review and purge historical CI logs, agent transcripts, and debugging records that may already contain device tokens.

  8. Revoke and regenerate tokens that may have been exposed through prior executions.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

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

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The request destination is derived from JF_ENDPOINT, an environment variable, and the code sends signed authentication headers including uuid, appKey, and signature to that host. If an attacker can influence the runtime environment, they can redirect requests to an attacker-controlled domain and exfiltrate authenticated request metadata or induce unauthorized device-management actions.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 63)May include surrounding context.

python
"Name": "Ability.AovAbility"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

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

Critical
Category
Data Flow
Confidence
95% confidence
Finding

This call also uses a URL built from the untrusted JF_ENDPOINT environment variable and transmits authenticated headers to the selected server. A malicious endpoint could harvest request metadata and receive device configuration queries, creating credential-leakage and SSRF-like outbound redirection risk.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 96)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

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

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The setconfig operation sends authenticated, state-changing requests to a host controlled by JF_ENDPOINT. If that environment variable is tampered with, an attacker can receive signed requests and potentially trigger unauthorized configuration changes or capture sensitive request material intended for the vendor API.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 129)May include surrounding context.

python
}
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") != 2000:

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill includes functionality to obtain and process device tokens, but this sensitive credential-handling capability is not prominently declared as part of the skill's purpose. Hidden or under-documented token acquisition increases the risk of accidental credential exposure, misuse, or overbroad trust in a skill that appears to only adjust battery thresholds.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill includes functionality to obtain and process device tokens, but this sensitive credential-handling capability is not prominently declared as part of the skill's purpose. Hidden or under-documented token acquisition increases the risk of accidental credential exposure, misuse, or overbroad trust in a skill that appears to only adjust battery thresholds.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `SKILL.md` | 技能文档 |

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script prints the retrieved device token in plaintext and even suggests exporting it into an environment variable, increasing the chance of disclosure through terminal scrollback, recordings, shared shells, or log capture. Because the token appears to grant device access, exposure can enable unauthorized use of downstream device-management APIs.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documentation describes use of environment variables and outbound network access, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens review and runtime containment because consumers cannot easily tell that the skill can read secrets from the environment and call remote APIs with them.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

L017-L019 将“低电量模式”“电池管理”“电量配置”列为触发词,其中“电池管理”“电量配置”范围较宽,可能覆盖日常设备讨论或其他电源相关任务,缺少明确约束。文档也未提供负例或限定仅在特定设备/平台上下文中触发,容易产生非预期调用。

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

L041-L044 的“触发词”仅给出并列短语,没有说明哪些表述一定触发、哪些近义表述不触发,也未限定是查询还是设置操作如何区分。对于会修改设备配置的技能,这种模糊边界会增加错误调用或误执行配置变更的风险。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

SQP-3 applies to all file types and includes language or locale policy violations. The module docstring and subsequent inline documentation are presented exclusively in Chinese, with no indication that users may choose another language or that the skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 63)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") == 2000:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 96)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") == 2000:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/battery_manage.py (reported line 129)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") == 2000:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/get_current_threshold.py (reported line 54)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") == 2000:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/get_device_token.py (reported line 72)May include surrounding context.

python
"Name": "Dev.LowElectrMode"
    }
    
    response = requests.post(url, headers=headers, json=body, timeout=30)
    result = response.json()
    
    if result.get("code") == 2000:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes a battery-management skill that queries and sets low-battery thresholds, but this script's primary behavior is to authenticate against a remote RTC endpoint and retrieve a device token. Token acquisition may support later battery operations, but exposing a standalone credential/token retrieval flow is broader than the stated battery-management behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script prints the raw API response body directly, which may contain sensitive data such as device tokens, identifiers, or backend error details. If logs are captured by terminals, CI systems, shell history tooling, or centralized logging, this can leak credentials and operational metadata to unauthorized parties.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

For a skill presented as managing battery thresholds, this code consumes high-privilege credentials (uuid, appKey, appSecret) and uses them to generate signed requests and obtain device tokens from a remote API. That authentication/token-minting capability is not itself justified by the narrow end-user purpose stated in the manifest.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

L003 及全文均以中文描述技能能力与使用方式,但未声明这是面向中文用户的区域化技能,也未提供语言选择或用户偏好说明。按自然语言策略,强制单一语言而无用户选择可能构成语言/区域策略问题。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring and user-facing descriptions are written only in Chinese, which imposes a specific language on users without any stated opt-in or alternative. The stated policy flags language/locale constraints when they are forced rather than optional or justified.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The manifest describes a device battery-management skill for querying and setting low-battery thresholds. While API authentication is expected, directly sourcing credentials and identifiers from process environment variables adds a broader host-context access capability not stated in the skill purpose or description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file’s docstrings and all CLI-facing messages are written in Chinese, which imposes a specific language on users. There is no opt-in, fallback, or documentation indicating that this skill is intentionally limited to Chinese-speaking users or a China-specific operational context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings in the module docstring and CLI output are fixed to Chinese, which forces a specific language experience without user opt-in. This can violate language or locale policy where tools are expected to be language-neutral or to offer a choice.

Content

No source excerpt is available for this finding.