Back to skill

Security audit

指数直通车ETF信息查询

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed ETF data-query skill that needs an API key and network access to its ETF service, with no evidence of hidden exfiltration, trading, persistence, or privilege escalation.

Install only if you are comfortable giving this skill an Index Hub API key and letting it query the ETF service over the network. Keep the default skills directory unless you have a specific reason to change it, and treat the stored API key file as a local secret.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (20)

Tainted flow: 'request' from os.environ.get (line 342, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/api_client.py (reported line 352)May include surrounding context.

python
"X-Caller-Type": getattr(config, "CALLER_TYPE", "external"),
        },
    )
    with urllib.request.urlopen(request, context=ssl.create_default_context(), timeout=timeout) as response:
        raw = response.read().decode("utf-8")
    return validate_result(json.loads(raw))

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is presented as a data-query tool, but the file also describes installation, credential collection/storage, reading local configuration files, and remote connectivity/auth smoke testing. Those behaviors materially expand the attack surface because the skill interacts with secrets and the local filesystem, and a user may authorize it under a much narrower mental model. In this context, undeclared credential handling is especially sensitive because API keys are persisted in standard user locations and may be exposed or misused by other components.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as a data-query tool, but the file also describes installation, credential collection/storage, reading local configuration files, and remote connectivity/auth smoke testing. Those behaviors materially expand the attack surface because the skill interacts with secrets and the local filesystem, and a user may authorize it under a much narrower mental model. In this context, undeclared credential handling is especially sensitive because API keys are persisted in standard user locations and may be exposed or misused by other components.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is presented as a data-query tool, but the file also describes installation, credential collection/storage, reading local configuration files, and remote connectivity/auth smoke testing. Those behaviors materially expand the attack surface because the skill interacts with secrets and the local filesystem, and a user may authorize it under a much narrower mental model. In this context, undeclared credential handling is especially sensitive because API keys are persisted in standard user locations and may be exposed or misused by other components.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The script deletes ${SKILLS_DIR}/${SKILL_NAME} recursively, and SKILLS_DIR is user-controllable via --skills-dir or environment. Although ${SKILL_NAME} is constrained to the script directory basename and ${SKILLS_DIR:?} prevents an empty variable, the script does not canonicalize or constrain SKILLS_DIR to an expected safe base, so a mistaken or manipulated target path could cause unintended data deletion in an arbitrary filesystem location accessible to the user.

Content

Scanner excerpt · install.sh (reported line 142)May include surrounding context.

sh
stage 4 "安装功能"
if [[ "$DO_INSTALL" -eq 1 ]]; then
  rm -rf "${SKILLS_DIR:?}/${SKILL_NAME}"
  # -L turns symlinks into ordinary files. Installed skills are
  # therefore self-contained even when this script is run from the repository.
  cp -RL "$SCRIPT_DIR" "${SKILLS_DIR}/${SKILL_NAME}" || fail "复制 ${SKILL_NAME} 失败。" "检查 ${SKILLS_DIR} 权限。"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares access to environment variables, local files, network, and shell-like execution behavior but does not publish an explicit permission or allowed-tools scope. That creates an overprivileged trust boundary: a host or reviewer cannot quickly determine which capabilities are actually required, and the skill also handles API keys and local config paths, increasing the chance of unintended credential or filesystem exposure. In this context, the risk is real but moderated because the document also constrains usage to a specific API client rather than arbitrary exfiltration logic.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Line L015 states that the skill converts '中文自然语言' ETF queries, which imposes a Chinese-language constraint in the skill instructions. The file does not offer an opt-in language choice or clearly document that the skill is intentionally limited to a China-specific locale for policy or compliance reasons.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The ETF skill loads credentials from ~/.config/index-hub/api_key, which belongs to a differently named service context. Reusing an unrelated credential location can cause confused-deputy behavior, where this skill silently consumes credentials intended for another tool or product and gains network access the user did not clearly authorize for this skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring and runtime error text are written entirely in Chinese, which imposes a specific language on users. Under the policy rule, forcing a language without user opt-in or a documented justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code accesses sensitive credentials from both environment variables and a file under the user's home directory. Although the module docstring documents the lookup order, there is no explicit user-facing warning, confirmation, or disclosure about reading sensitive credential sources, which matches the missing-warning criterion for code files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The file appends a fixed disclaimer written entirely in Chinese to every finalized answer. This imposes a specific language on all users without any visible opt-in, fallback, or locale-selection mechanism, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script's prompts, error messages, and status output are presented in Chinese throughout, including installation guidance and API key prompts. For a general-purpose installer, this imposes a specific language on users without opt-in or justification, which matches the locale-policy violation criteria.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

Scanner excerpt · install.sh (reported line 154)May include surrounding context.

sh
fi

mkdir -p "$CREDENTIALS_DIR" || fail "无法创建凭据目录:$CREDENTIALS_DIR" "检查 HOME 目录权限。"
chmod 700 "$CREDENTIALS_DIR" || fail "无法收紧凭据目录权限。" "检查 $CREDENTIALS_DIR 的所有权。"
CREDENTIALS_TMP="$(mktemp "${CREDENTIALS_FILE}.tmp.XXXXXX")" || fail "无法创建临时凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
chmod 600 "$CREDENTIALS_TMP" || fail "无法设置临时凭据文件权限。" "检查文件系统权限。"
printf '%s\n' "$API_KEY" > "$CREDENTIALS_TMP" || fail "无法写入凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

Scanner excerpt · install.sh (reported line 156)May include surrounding context.

sh
mkdir -p "$CREDENTIALS_DIR" || fail "无法创建凭据目录:$CREDENTIALS_DIR" "检查 HOME 目录权限。"
chmod 700 "$CREDENTIALS_DIR" || fail "无法收紧凭据目录权限。" "检查 $CREDENTIALS_DIR 的所有权。"
CREDENTIALS_TMP="$(mktemp "${CREDENTIALS_FILE}.tmp.XXXXXX")" || fail "无法创建临时凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
chmod 600 "$CREDENTIALS_TMP" || fail "无法设置临时凭据文件权限。" "检查文件系统权限。"
printf '%s\n' "$API_KEY" > "$CREDENTIALS_TMP" || fail "无法写入凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
mv "$CREDENTIALS_TMP" "$CREDENTIALS_FILE" || fail "无法保存凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
chmod 600 "$CREDENTIALS_FILE" || fail "无法收紧凭据文件权限。" "检查 $CREDENTIALS_FILE 的所有权。"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

Scanner excerpt · install.sh (reported line 159)May include surrounding context.

sh
mkdir -p "$CREDENTIALS_DIR" || fail "无法创建凭据目录:$CREDENTIALS_DIR" "检查 HOME 目录权限。"
chmod 700 "$CREDENTIALS_DIR" || fail "无法收紧凭据目录权限。" "检查 $CREDENTIALS_DIR 的所有权。"
CREDENTIALS_TMP="$(mktemp "${CREDENTIALS_FILE}.tmp.XXXXXX")" || fail "无法创建临时凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
chmod 600 "$CREDENTIALS_TMP" || fail "无法设置临时凭据文件权限。" "检查文件系统权限。"
printf '%s\n' "$API_KEY" > "$CREDENTIALS_TMP" || fail "无法写入凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
mv "$CREDENTIALS_TMP" "$CREDENTIALS_FILE" || fail "无法保存凭据文件。" "检查 $CREDENTIALS_DIR 的写入权限。"
chmod 600 "$CREDENTIALS_FILE" || fail "无法收紧凭据文件权限。" "检查 $CREDENTIALS_FILE 的所有权。"

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes an ETF-focused skill covering ETF information, holdings-based ETF lookup, rankings, and ETF market data. Lines L533-L551 document a separate quote/stock/list capability for direct individual stock real-time quotes, which is only loosely justified as a supplement and is not part of the declared ETF query scope.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file-level documentation says this is a client for the 'Index Hub API', while the enclosing skill manifest is for an ETF query skill. The code also reinforces that broader identity via names like INDEX_HUB_* and an error message referencing 'Index Hub', which contradicts the documented skill intent and suggests reused infrastructure whose stated purpose does not match this skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The code pulls API credentials from environment variables and a home-directory file, which gives the skill access to secrets from the host environment. In an agent-skill setting, undeclared secret ingestion expands the trust boundary and may violate least-privilege expectations, especially when the manifest does not justify local file or environment secret access.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest centers on ETF information and ETF-related screening/comparison/market data. Lines L555-L572 add a discovery/fund-manager-list endpoint for fuzzy searching management companies, which is a generic directory/discovery function not clearly justified by the stated ETF-query purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code contains multiple user-facing strings in Chinese, including errors and command-line help text, and does not provide any option to select a different language or locale. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/api_client.py:72