Back to skill

Security audit

查询全国油价

Security checks for vulnerabilities and agentic risk

Overview

This oil-price skill is domain-aligned, but it has a reachable unsafe parsing flaw and misleading behavior around historical and nationwide queries.

Review before installing. The skill does not show credential theft or destructive intent, but the referenced scripts should be fixed to parse API responses as data, not executable Python source. Also treat historical and nationwide results cautiously because the documentation overstates what some scripts actually return, and avoid adding the scripts directory to ~/.bashrc unless you intentionally want persistent PATH changes.

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/oil_price.sh:60
Finding

Remote API Response Injection Enables Arbitrary Python Code Execution in Real-Time Price Query

Content
View full analysis

Vulnerability Details

File Location: scripts/oil_price.sh:60-76
Vulnerability Type: Remote data injected into generated Python source
Risk Level: High

Vulnerable Code

bash
local url="https://map.360.cn/app/qcms?req=oil_price&cityid=${cityid}"

# Use curl to retrieve data and process JSONP
local response=$(curl -s "${url}" 2>/dev/null | sed 's/.*callback([^{]*)({).*/\1/g' | sed 's/}$//')

if [ -z "$response" ] || [ "$response" == "null" ]; then
    echo "Unable to retrieve oil-price data"
    return 1
fi

# Parse JSON and format output
python3 << PYEOF
import json
import sys

try:
    data = json.loads('''${response}''')

Technical Analysis

The script obtains a response from the external map.360.cn API and interpolates the response directly into an unquoted shell heredoc containing Python source code:

python
data = json.loads('''${response}''')

Although the response is intended to be JSON, it is not passed to Python as data. It becomes part of the Python program before the interpreter parses that program. A response containing a closing triple quote, Python statements, and a suitable comment or trailing expression can escape the json.loads string literal and introduce arbitrary Python code.

For example, the structural form of a malicious response could terminate the string with ''', append Python statements, and comment out or otherwise neutralize the remaining source on that line. The injected statements would run when the heredoc is passed to python3, before JSON validation could provide any protection.

HTTPS protects the connection against ordinary on-path modification when certificate validation succeeds, but it does not make the response safe to interpret as source code. The external API provider, a compromised API endpoint, or any actor capable of controlling a valid API response remains across a trust boundary.

Attack Path

  1. A user or agent invokes the documented entry point:
    bash
    scrip
    

...[truncated 1188 chars]

Remediation
View remediation

Remediation Suggestions

Never interpolate network responses into Python source code. Pass the response through standard input or a securely created temporary file and parse it strictly as data.

A standard-input design can use:

bash
if ! curl -fsS "$url" | python3 -c '
import json
import sys

data = json.load(sys.stdin)
# Validate and format the expected fields here.
'; then
    echo "Unable to retrieve or parse oil-price data" >&2
    return 1
fi

Alternatively:

  1. Create a temporary file with mktemp.
  2. Install a cleanup trap immediately.
  3. Write the response to that file without evaluating it.
  4. Pass only the file path as a Python argument.
  5. Parse it with json.load.
  6. Validate the top-level type, required fields, field types, and reasonable response size.

Example:

bash
tmpfile=$(mktemp) || return 1
trap 'rm -f "$tmpfile"' RETURN

curl -fsS --max-time 15 --max-filesize 1048576 "$url" > "$tmpfile" || return 1

python3 - "$tmpfile" <<'PYEOF'
import json
import sys

with open(sys.argv[1], "r", encoding="utf-8") as handle:
    data = json.load(handle)

if not isinstance(data, dict):
    raise ValueError("Unexpected response structure")
PYEOF

Quote the heredoc delimiter (<<'PYEOF') whenever the heredoc contains fixed program source so that shell interpolation cannot modify that source.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/oil_history.sh:45
Finding

Remote API Response Injection Enables Arbitrary Python Code Execution in Historical Price Query

Content
View full analysis

Vulnerability Details

File Location: scripts/oil_history.sh:45-64
Vulnerability Type: Remote data injected into generated Python source
Risk Level: High

Vulnerable Code

bash
local url="https://map.360.cn/app/qcms?req=oil_history&cityid=${cityid}"

echo "Retrieving historical oil-price data..."

# Use curl to retrieve data
local response=$(curl -s "${url}" 2>/dev/null)

if [ -z "$response" ]; then
    echo "Unable to retrieve historical oil-price data"
    return 1
fi

# Parse and format output
python3 << PYEOF
import json
import sys
from datetime import datetime

try:
    data = json.loads('''${response}''')

Technical Analysis

The historical-price entry point embeds the complete body returned by an external service inside a triple-quoted Python string in an unquoted heredoc:

python
data = json.loads('''${response}''')

json.loads does not mitigate the issue because Python must first parse and execute the generated program. A crafted response can close the triple-quoted literal and inject Python statements outside the json.loads argument.

The vulnerable operation occurs automatically during every successful historical-price request. There is no response sanitization, source-code escaping, isolation boundary, or confirmation step between the network response and the Python interpreter.

The trust boundary is crossed when data controlled by the external API is transformed into locally executed Python source. The fact that the request uses HTTPS does not protect against a malicious or compromised endpoint returning a syntactically crafted body.

Attack Path

  1. A user or agent invokes the documented historical-price script with a supported province:
    bash
    scripts/oil_history.sh Beijing
    
  2. The script requests historical data from the external API.
  3. The endpoint supplies a response that closes the '''...''' Python string and adds executable Python statements.
  4. Shell parameter expansion places t ...[truncated 875 chars]
Remediation
View remediation

Remediation Suggestions

Separate executable Python source from remote response data. Do not embed ${response} in a heredoc.

Pass the body through standard input:

bash
curl -fsS --max-time 15 "$url" | python3 -c '
import json
import sys
from datetime import datetime

data = json.load(sys.stdin)
if not isinstance(data, dict):
    raise ValueError("Unexpected response structure")
# Continue formatting validated fields.
'

For a larger parser, place the Python implementation in a static .py file and invoke it with the response file path:

bash
tmpfile=$(mktemp) || return 1
trap 'rm -f "$tmpfile"' RETURN

curl -fsS --max-time 15 --max-filesize 1048576 "$url" > "$tmpfile" || return 1
python3 "$SCRIPT_DIR/oil_history_parser.py" "$tmpfile"

The parser should:

  • Use json.load on the file or json.load(sys.stdin).
  • Enforce a response-size limit.
  • Require the expected top-level JSON type.
  • Validate all expected arrays, objects, dates, fuel names, and numeric values.
  • Reject unexpected structures instead of attempting to evaluate or decode them as program text.
  • Avoid printing stack traces containing sensitive local context in normal operation.
  • Use a quoted heredoc delimiter for any remaining static heredoc source.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述的是一个较完整的油价查询能力集合,包括实时与历史油价、按省份或直辖市查询,以及全国概览。提供的代码片段则是一个专门用于“全国油价概览”的 shell 脚本:它内置省份映射,循环请求远程接口获取实时油价,并调用 oil_price.py 解析显示结果。就该代码片段本身而言,未看到历史油价相关逻辑,也没有用户输入或参数处理来支持单省/直辖市定向查询。因此,代码行为只覆盖了声明中的一部分能力。另一个小差异是输出表头含89号汽油,而声明只列出92/95/98和0号柴油。综合看,声明范围明显大于该代码片段实际实现,属于描述与代码行为不完全一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

声明描述的是一个完整的中国油价查询技能,涵盖实时油价、历史油价、按省份或直辖市查询,以及全国概览,并强调返回 92/95/98 号汽油和 0 号柴油价格。但此代码块只是一个“历史油价解析模块”:它从临时文件读取 JSON,标准化日期,筛选日期范围,并格式化打印历史记录。代码没有任何实时油价查询逻辑,也没有全国概览功能。更重要的是,代码还明确警告 API 返回城市可能与查询省份不匹配,说明历史查询并不真正支持按省份稳定查询。燃油类型方面,代码实际重点处理 89、92、95 和 0 柴油,虽然标准名称表中包含 98 号汽油,但历史名称映射中没有对应项,因此与声明的返回油号也不完全一致。因此该代码块与整体声明存在实质性能力不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

描述声称该技能可查询中国各省实时油价和历史油价,并支持按省份/直辖市查询及全国概览。但代码片段明确是 oil_history.sh,只处理历史油价场景。更重要的是,代码中直接写明“历史油价 API 目前只支持查询上海”,并无论用户输入哪个省份/城市,都使用固定 SHANGHAI_CODE="310000" 调用接口 req=oil_history&cityid=310000。这意味着它并不能按声明那样返回各省对应的历史油价。另有省份/城市映射,但仅用于校验输入,未用于实际历史查询。代码中也没有实时油价查询逻辑,未体现全国油价概览能力。因此,代码行为与声明的核心能力存在实质性不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

该代码的核心功能与油价查询总体相关,但与声明存在实质性偏差。它并不实现“全国油价概览”,因为逻辑只接受一个 province_code 并在 cities 列表中匹配单一目标省份。它也不真正支持“历史油价查询”,仅使用 last 字段显示上次价格并计算涨跌,不能视为完整的历史数据查询能力。另外,代码实际处理并展示 89 号汽油,而声明仅列出 92/95/98 号汽油及 0 号柴油。未发现与声明无关的敏感资源访问或越权行为,但功能描述与实际行为不完全一致,因此应判定为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code’s core purpose is related to oil price lookup, so it is broadly aligned with the domain. However, the declared description claims support for historical oil prices and a nationwide overview, neither of which is implemented in the provided shell script. The script only accepts a single input, resolves it to a province code, fetches one province’s current oil-price data from an external API, and passes the response to a Python parser. The help text mentions showing current and previous prices/trends, but that is not the same as a general historical price query capability, and the historical behavior is not evident in this chunk. Additionally, the script supports city-name input and 89-octane fuel, which are not reflected in the description. Therefore the description does not accurately represent the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

整体上,这段代码的主要目的与声明大体一致,确实是在查询中国各省油价,并支持实时、历史和全国概览。但存在若干实质性偏差。首先,全国概览脚本表头声称会显示 92/95/98/0# 柴油列,但实际只计算并输出每个省的平均价格,未返回描述中承诺的各油号价格。其次,实时油价脚本额外查询和展示了 89 号汽油,这属于未声明的能力扩展。再次,历史油价脚本按日期汇总上调/下调项目,表现为调价记录,而不是清晰的历史价格列表明细。没有发现与声明无关的敏感行为(如数据外传、执行额外系统操作等),但功能呈现与描述存在一定不一致,因此应判定为 mismatch。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description promises a user-facing oil price query capability with specific fuel price outputs and support for province-based and nationwide overview queries. However, the supplied code chunk merely reads a local JSON file of province codes and prints those codes. While this may be a helper step for a larger implementation, the actual behavior in this chunk does not match the declared purpose of querying and returning oil prices. Therefore, this code chunk materially under-implements the claimed functionality and should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

代码的核心功能是历史油价查询:它要求提供一个省份参数,从本地省份编码文件中解析 cityid,然后请求 https://map.360.cn/app/qcms?req=oil_history&cityid=... 获取历史数据并按日期展示。代码中没有任何用于查询“实时油价”的逻辑,也没有全国概览或无参全国查询逻辑。虽然输出的历史记录中可能包含各油品价格,但这属于历史调价明细,不等同于声明的“实时油价和全国油价概览”能力。因此描述明显覆盖了代码未实现的重要能力,构成不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

代码的核心功能确实是按省份查询中国地区油价,整体方向与描述相近;但声明中包含两项重要能力与实际不符。第一,所谓“历史油价”并未实现,代码只展示当前价格和接口返回的 last 字段(上次价格),没有按日期范围、历史记录列表或历史查询逻辑。第二,声明称支持“全国油价概览”,但脚本在未提供参数时仅打印帮助信息并退出,没有全国汇总查询。另一个较小差异是输出油品种类并不严格限制在92/95/98号汽油和0号柴油,代码还会处理89号等接口返回项目。综合来看,描述夸大了实际能力,属于描述与行为不完全一致。

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
87% confidence
Finding

Appending a new scripts directory to ~/.bashrc is a persistence mechanism that causes future shells to trust executables from that location. Although this specific line is not a backdoor by itself, it creates a durable execution foothold and can increase the impact of any subsequent file tampering or malicious script drop into that directory.

Content

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

e/skills/oil-price-query/scripts/install.sh

text

### 方法 3:手动安装
```bash
# 创建技能目录
mkdir -p ~/.openclaw/workspace/skills/oil-price-query

# 复制脚本文件
cp ~/.openclaw/workspace/skills/oil-price-query/scripts/*.sh ~/.openclaw/workspace/skills/oil-price-query/

# 添加执行权限
chmod +x ~/.openclaw/workspace/skills/oil-price-query/*.sh

# 添加到 PATH(可选)
echo "export PATH=$HOME/.openclaw/workspace/skills/oil-price-query/scripts:$PATH" >> ~/.bashrc
source ~/.bashrc

验证安装

bash
# 测试实时油价查询
oil_price.sh 北京

# 测试历史油价查询
oil_history.sh 北京

# 测试全国概览
oil_all.sh

注意事项

  1. 省份名称匹配:支持省份全称和常用简称(如:北京/京、广东/粤)
  2. 数据实时性:油价数据可能延迟更新,以官网数据为准
  3. 部分省份无 89#汽油:部分省份(如内蒙古、辽宁、吉林、黑龙江、河南、湖北、湖南等)已�

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script accepts a province/city argument, validates it, then deliberately ignores it and always queries Shanghai history data. This is a data integrity and deceptive-behavior issue: downstream users or agents may trust the result as location-specific and make decisions based on false information despite the warning text.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises executable shell-based workflows and file/environment access but does not declare any explicit tool scope or permissions boundary. That makes the skill harder to sandbox and review, and increases the chance an agent may invoke shell or file operations more broadly than a user expects.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation includes installation behavior that changes the user's shell environment, even though the core purpose is simply querying oil prices. Persistent shell modification is security-relevant because it affects future sessions and expands the blast radius of any later script replacement or PATH hijacking involving that directory.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

A one-click installer with no disclosure of its system changes reduces informed consent and makes it difficult to assess persistence, PATH edits, permissions changes, or other side effects. In agent or automation contexts, opaque installers are especially risky because they may normalize unattended host modification.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

Creating a persistent directory and copying executable scripts into the user's workspace establishes durable state across sessions. By itself this is common installation behavior, but in combination with PATH modification it becomes more security-relevant because later executions may trust files in that location automatically.

Content

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

方法 3:手动安装

bash
# 创建技能目录
mkdir -p ~/.openclaw/workspace/skills/oil-price-query

# 复制脚本文件
cp ~/.openclaw/workspace/skills/oil-price-query/scripts/*.sh ~/.openclaw/workspace/skills/oil-price-query/

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instructions append to ~/.bashrc without an explicit warning that this is a persistent system change. Users may unknowingly trust future commands from that added directory, creating a long-lived execution path that outlives the immediate installation session.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The usage text explicitly advertises arbitrary province/city historical queries, but the implementation later ignores the requested location and fetches fixed Shanghai data. This mismatch can mislead users and other automation into believing results are scoped to their requested region, causing silent integrity failures.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Comments, usage strings, status output, and error messages are all presented in Chinese, which effectively forces a specific language for users. The file does not offer an opt-in language choice or explain that the skill is intentionally restricted to a Chinese-language or region-specific audience.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says the skill supports both 历史油价 and 全国油价概览, but the implemented flow in this file resolves one city/province input and performs a single API call for that province only. There is no code here to fetch historical records or aggregate/display a nationwide overview, creating a clear description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This shell script embeds comments, prompts, usage text, and generated child-script output entirely in Chinese, effectively forcing a specific language/locale for all users. Under the policy, language constraints should either offer user choice or be clearly documented as a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill documentation is entirely written in Chinese and presents the skill as specifically for Chinese provinces and commands without any indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern unless the locale constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON manifest-like data file uses Chinese-only keys and values throughout, which can impose a language/locale constraint without documenting user opt-in or a justified region-specific scope. The policy allows locale constraints when clearly documented and justified, but this file contains no natural-language indication that the skill is China-specific or that Chinese is an intentional requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The user-facing comments and console output are entirely in Chinese, including the usage text and status messages. This imposes a specific language/locale on all users without any opt-in or documented region-specific justification in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code file contains natural-language instructions and output strings that assume Chinese as the only interaction language. Under the policy, forcing a specific language without user opt-in can be a locale/language policy violation unless the constraint is explicitly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The script persists API response content in a temporary file and writes parser output to a predictable path under /tmp. Even if the data is not highly sensitive here, local persistence can expose queried data to other local users/processes, leave residual artifacts, and create avoidable privacy and operational leakage.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.