Back to skill

Security audit

Fund Keeper

Security checks for vulnerabilities and agentic risk

Overview

This fund-advisor skill is mostly coherent, but it has review-worthy financial-data integrity, persistence, and disclosure problems that users should understand before installing.

Install only if you are comfortable with a finance tool that contacts multiple public market-data services, writes local portfolio records, and may run recurring scheduled tasks if you enable them. Treat its investment suggestions as unverified reference output, avoid using the sample stock rankings for decisions, remove bundled portfolio data before use, and prefer running it in a dedicated environment with restricted network and file access.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (6)

T06 · System Persistence

Error
Location
SKILL.md:209
Finding

Documented recurring OpenClaw tasks create cross-session persistence

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding

Third-party Python dependencies are installed without immutable version and integrity controls

Content
View full analysis
=1.12", "pandas>=2.0", "requests>=2.28", "easyocr>=1.7"] ``` The installation workflow also uses unconstrained package installation: ```bash pip install akshare pandas requests easyocr ``` Another installation path states: ```bash pip install requests pandas ``` ### Technical Analysis The package constraints are either absent or lower-bound-only. They allow the resolver to select arbitrary future versions and mutable transitive dependencies from the operator's configured Python package index. The project contains no lockfile, package hashes, signed artifact policy, or reproducible dependency manifest. EasyOCR also obtains model artifacts at runtime when they are not already present. The project does not pin or verify the integrity of those model files. This is a supply-chain exposure rather than evidence that the currently named packages are malicious. Exploitation requires a compromised package index, mirror, package release, transitive dependency, or runtime model source. ### Attack Path 1. A user follows the installation instructions. 2. `pip` resolves the latest compatible direct and transitive package versions from the configured index. 3. An attacker-controlled or compromised package release is selected. 4. Package installation hooks or imported module code executes under the installing user's account. 5. The compromised dependency gains access to the same local portfolio files, process environment, and network permissions as the Skill. ### Impact Assessment A malicious dependency can execute Python code with the privileges of the user running installation or the Skill. That scope can include reading or modifying portfolio records, transaction ...[truncated 260 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
fund_keeper.py:180
Finding

Unauthenticated HTTP market data can be manipulated to alter financial recommendations and cached results

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
stock_data.py:120
Finding

Runtime network destinations exceed the Skill's declared domain boundary

Content
View full analysis
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Error
Location
stock_data.py:120
Finding

Hard-coded sample rankings are presented as current stock-market results

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
funds/my-funds.md:5
Finding

Release package contains populated private portfolio and performance records

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (49)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the implementation performs stock-market queries against Sina Finance and 10jqka while presenting itself as a fund advisor and not declaring those domains, users and platform policy controls may be misled about actual outbound traffic. Undeclared network destinations are security-relevant because they expand the trust boundary and can exfiltrate usage patterns or retrieved financial data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes the skill as a Chinese mutual fund advisor, with stock-fund linkage as a supporting feature. This changelog adds direct stock market capabilities such as real-time individual stock quotes and market gainers/losers lists, which are broader than merely linking stocks to funds and represent an expanded behavior scope.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language README content, including the tagline, features, commands, and audience sections, is presented entirely in Chinese. Under the policy, forcing a specific language without user opt-in or a documented justification is a locale/language policy issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The markdown lists edit, remove, buy, and sell commands, and elsewhere states the tool maintains files such as my-funds.md and transactions.json. However, the README does not warn users that these commands will modify or delete local data, which is a user-data-impacting behavior that should be disclosed in markdown descriptions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill declares network requirements and clearly instructs users to read and write portfolio/config files, but it does not define an explicit tool scope such as permissions or allowed-tools. That creates a governance gap where the runtime may grant broader file or network access than users expect, increasing the risk of unintended data exposure or capability abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The description explicitly frames the skill as a 'Chinese mutual fund intelligent advisor,' which imposes a locale-specific scope in the natural-language description. The file does not clearly offer users a language or locale choice or explain that the locale limitation is an intentional regional constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The file-level description states the tool is a domestic Chinese fund advisor, and the user-facing prompts and outputs throughout the CLI are predominantly hard-coded in Chinese. There is no indication that users can opt into another language or locale, which may violate language-choice policy for generally available skills.

Content

No source excerpt is available for this finding.

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 185)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 224)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 249)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1383)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1408)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1436)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1460)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1607)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 1657)May include surrounding context.

python
"User-Agent": "Mozilla/5.0",
                    "Referer": f"http://fund.eastmoney.com/{fund_code}.html"
                }
                response = requests.get(url, headers=headers, timeout=5)
                if response.status_code == 200:
                    content = response.text
                    if content.startswith("jsonpgz(") and content.endswith(");"):

Tainted flow: 'url' from input (line 1652, user input) → requests.get (network output)

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 · fund_keeper.py (reported line 413)May include surrounding context.

python
try:
            url = f"http://fund.eastmoney.com/f10/jjjz_{fund_code}.html"
            headers = {"User-Agent": "Mozilla/5.0"}
            response = requests.get(url, headers=headers, timeout=10)
            
            if response.status_code == 200:
                import re

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The OCR feature reads user-supplied screenshots and extracts text, including any incidental sensitive data present in the image, without a clear warning or consent prompt. In a finance-oriented skill, screenshots may contain account balances, names, transaction history, or unrelated private content, making silent extraction more sensitive than in a generic OCR utility.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is presented as a mutual-fund advisor but contains additional precious-metals pricing and investment-advice functionality outside the declared scope. Scope expansion matters because users and hosting systems may grant trust, permissions, or expectations based on the manifest; hidden or undocumented financial-advice features increase surprise and risk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.