Back to skill

Security audit

Fund Ai Assistant

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent fund-analysis assistant, but it misstates where LLM keys and portfolio data are sent and can transmit detailed holdings externally.

Review llm.py before use. Do not set a third-party LLM key expecting LLM_API_BASE to route it elsewhere, because this version sends LLM requests to OpenAI. Treat analysis as externally processed and assume exact holdings, transaction dates, prices, quantities, and notes may be included in prompts. Use a dedicated low-limit API key, avoid sensitive notes in positions.json, and only configure push/webhook URLs you control.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
llm.py:51
Finding

Documented Custom LLM Endpoint Is Ignored, Potentially Disclosing Third-Party API Keys to OpenAI

Content
View full analysis
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
macro_fetcher.py:132
Finding

Untrusted Tavily Search Results Are Inserted Directly into LLM Investment Prompts

Content
View full analysis
str: """将宏观数据格式化为 prompt 注入区块""" if not macro or not macro.get("ok"): return "" lines = [ "\n## 【宏观局势背景】(以下信息由 AI 自动抓取,请结合分析)", f"抓取时间:{macro.get('fetch_time', '—')}", "", "【国内宏观】", macro.get("china", "(数据获取失败)"), "", "【国际宏观】", macro.get("global_market", "(数据获取失败)"), "", "【市场与金融行业影响】", macro.get("financial_impact", "(数据获取失败)"), "", "⚠️ 以上信息仅供分析参考,请结合基金的实际情况综合判断。", ] return "\n".join(lines) ``` The resulting external content is then included in the LLM prompt: ```python def _build_macro_section(macro_data: dict) -> str: """从 macro_fetcher 导入并构建宏观局势区块""" try: from macro_fetcher import format_macro_section return format_macro_section(macro_data) if macro_data else "" except Exception: return "" ``` ```python position_section=_build_position_section(position, nav), macro_section=macro_section, ``` ### Technical Analysis Tavily search results contain text derived from external webpages. The Skill treats these snippets as ordinary prompt text and does not establish a strong distinction between trusted instructions and untrusted retrieved data. A malicious or compromised webpage can include instruction-like content such as requests to disregard the analysis format, fabricate a recommendation, suppress risk warnings, or emit attacker-selected JSON fields. If Tavily returns that content, it is concatenated into the same user message as the investment-analysis instructions. The Skill validates only whether the final response parses as JSON. JSON parsing does not establish seman ...[truncated 1415 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
ai_analysis.py:213
Finding

Ordinary AI Analysis Transmits Detailed Portfolio and Transaction Information Without Granular Consent

Content
View full analysis
str: """构建持仓段落,若无持仓则返回提示""" if not position: return "(暂无持仓记录)" qty = position.get("total_quantity", 0) avg_cost = position.get("avg_cost", 0) total_cost = position.get("total_cost", 0) hold_days = position.get("hold_days", 0) current_value = current_nav * qty if current_nav and qty else 0 profit = (current_nav - avg_cost) * qty if current_nav and avg_cost else 0 profit_pct = (current_nav / avg_cost - 1) * 100 if current_nav and avg_cost else 0 buy_records = [r for r in position.get("records", []) if r["type"] == "buy"] lines = [ f"- 当前持仓:{qty}份", f"- 成本价:{avg_cost:.4f}元/份", f"- 总成本:{total_cost:.2f}元", f"- 当前市值:{current_value:.2f}元", f"- 浮动盈亏:{profit:+.2f}元({profit_pct:+.2f}%)", f"- 持仓天数:{hold_days}天", f"- 买入次数:{position.get('buy_count', 0)}次 | 卖出次数:{position.get('sell_count', 0)}次", f"- 各笔买入:", ] for r in buy_records: lines.append(f" · {r['date']} 买入 {r['quantity']}份 @ {r['price']:.4f}元 {'(' + r.get('note','') + ')' if r.get('note') else ''}") return "\n".join(lines) ``` The position section is included in the externally transmitted prompt: ```python prompt = FUND_ANALYSIS_PROMPT.format( fund_name=fund_name or fund_code, fund_code=fund_code, latest_nav=nav, est_change=est_change, latest_date=latest_date, ... position_section=_build_position_section(position, nav), macro_section=macro_section, ) raw = call_llm(model, prompt, api_key) ``` ### Technical Analysis The standard analysis path loads the user's local position record and embeds the following fields into an ...[truncated 1970 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
positions.py:33
Finding

Sensitive Portfolio Records Are Written with Process-Default Permissions and Non-Atomic Updates

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (64)

Tainted flow: 'tv_req' from os.environ.get (line 215, 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 · event_monitor.py (reported line 221)May include surrounding context.

python
headers={"Content-Type": "application/json"},
                method="POST",
            )
            with urllib.request.urlopen(tv_req, timeout=10) as tv_response:
                tv_data = json.loads(tv_response.read().decode("utf-8"))
            answer = tv_data.get("answer", "")
            m = re.search(r'7\.\d{3,4}', answer)

Tainted flow: 'req' from os.environ.get (line 64, 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 · llm.py (reported line 72)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=90) as resp:
            result = json.loads(resp.read().decode("utf-8"))
        choices = result.get("choices", [])
        if choices:

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

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

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

| Required | Description | |----------|----------|-------------| | LLM_MODEL | ✅ | Model name, e.g. gpt-4o-mini | | LLM_API_KEY | ✅ | Corresponding API key | | TAVILY_API_KEY | ❌ | Tavily API for real-time macro search | | PUSH_WEBHOOK_URL | ❌ | Webhook push (WeCom / Feishu / Slack) | | BARK_PUSH_URL | ❌ | iOS Bark notification | | PUSH_EMAIL | ❌ | Email push |


Crontab / Scheduler (Reference)

bash
# Macro event monitor (weekday morning)
openclaw cron add --cron "0 8 * * 1-5" \
  --message "cd /path/to/fund-ai-assistant && python3 event_monitor.py --dry-run"

# Fund tracking analysis (weekday morning)
openclaw cron add --cron "30 9 * * 1-5" \
  --message "cd /path/to/fund-ai-assistant && python3 analyzer.py analyze"

# Multi-agent debate (Friday morning)
openclaw cron add --cron "30 9 * * 5" \
  --message "cd /path/to/fund-ai-assistant && python3 debate_analyzer.py 000001"

灵感与来源 | Inspiration & Attribution

本项目的诞�

Tp4

High
Category
MCP Tool Poisoning
Confidence
84% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the actual implementation is focused on single-fund analytics rather than portfolio-level management, the issue is again inaccurate disclosure. In this finance context that matters because users may infer broader safeguards or data-processing expectations than the tool actually has.

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 99)May include surrounding context.

md
| `analyzer.py` | Main entry, tracking + analysis | `python3 analyzer.py list` |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documents capabilities that involve environment variables, local file access, file creation, and outbound network activity, but it does not declare any explicit tool scope or permissions. This weakens reviewability and consent because a user or host platform cannot easily tell what sensitive capabilities the skill expects before use.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The skill explicitly supports external transmission to LLM endpoints and other services, including use of a configurable API base. In a finance assistant, this is sensitive because fund data, prompts, and the API key may be sent off-host; a malicious or mistyped custom endpoint can exfiltrate credentials and investment data.

Content

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

md
| Variable | Description |
|----------|-------------|
| `LLM_API_BASE` | ⚠️ Custom API URL — if untrusted, your key and data go there. Use endpoints you control. Default: `https://api.openai.com/v1` |
| `TAVILY_API_KEY` | Tavily API for real-time macro search |
| `FUND_SCENE_DIR` | Directory with optional `.md` scene templates (default: `./scenes/`) |
| `PUSH_WEBHOOK_URL` | Generic HTTP POST webhook (WeCom / Feishu / Slack) |

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The recommended precautions confirm that the skill can send API keys and fund data to whatever LLM_API_BASE is configured. Even though the document warns about this, the capability remains a real security risk because the tool handles financial context and secret-bearing requests.

Content

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

md
### Recommended Precautions

1. **Use a dedicated LLM API key** — not your main production key.
2. **⚠️ Inspect `LLM_API_BASE`** — if set to an untrusted endpoint, your API key and fund data will be sent there. Only use `https://api.openai.com/v1` or endpoints you control.
3. **Review `llm.py` and `fund_api.py`** before first run.
4. **Run in an isolated environment** (container or VM) on first use.
5. **Do not set `FUND_SCENE_DIR`** to sensitive directories.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger list contains very generic terms such as "Fund," "portfolio," and "rebalance," which are likely to match ordinary financial conversations outside the skill's intended scope. Overly broad activation can cause the skill to engage unexpectedly and send user prompts or portfolio-related context to external services, increasing privacy and prompt-routing risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module explicitly instructs the LLM to provide 'professional, clear, actionable investment advice' including buy/sell actions, position sizing, stop-loss, and take-profit levels, but it does not attach a user-facing financial-risk warning or suitability disclaimer. In a fund-trading context, this can cause users to over-trust model output as personalized financial advice, increasing the risk of harmful or inappropriate investment decisions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The prompt is written entirely in Chinese and mandates a Chinese JSON schema and response behavior, which effectively fixes the skill's output language. Under the policy, forcing a specific language without user opt-in or a documented justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains user-facing natural language in the module docstring and command help text entirely in Chinese, which forces a specific language for interaction. The policy allows locale constraints only when the tool offers user choice or clearly documents a justified region-specific limitation, neither of which is present here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest emphasizes tracking, AI analysis, macro monitoring, technical indicators, and rebalancing alerts. In addition to those analytics functions, this file implements buy/sell record creation and record deletion commands, which change persisted position data and move the skill beyond passive tracking/analysis into portfolio bookkeeping and trade-log maintenance.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.