Back to skill

Security audit

fund-tracker

Security checks for vulnerabilities and agentic risk

Overview

This fund-tracking skill mostly does what it says, but it needs review because crafted preset names can make its history file logic read or overwrite JSON files outside the intended runtime folder.

Review before installing. Use a virtual environment or container, pin `npx` and Python dependency versions where possible, and keep preset names to simple letters, numbers, hyphens, or underscores. Expect the skill to fetch public fund data from AKShare/Eastmoney and write local history files for change tracking.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
tools/check.py:34
Finding

Path Traversal Through Unvalidated Preset Names

Content
View full analysis
Path: """Get history file path for a specific preset.""" return RUNTIME_DIR / f"history_{preset_name}.json" def load_history(preset_name: str) -> dict[str, dict[str, object]]: """Load previous check results for a preset.""" path = get_history_path(preset_name) if path.exists(): with path.open("r", encoding="utf-8") as f: return json.load(f) return {} def save_history(preset_name: str, current: dict[str, dict[str, object]]) -> None: """Save current results as history for next comparison.""" path = Path(get_history_path(preset_name)) path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8") as f: json.dump(current, f, ensure_ascii=False, indent=2) ``` The preset name is accepted when it exists as a key in the editable preset configuration: ```python presets = load_presets() if preset_name not in presets: print(json.dumps({ "error": f"Preset '{preset_name}' not found", "available": list(presets.keys()), }, ensure_ascii=False)) return 1 preset = presets[preset_name] ``` The resulting history is subsequently written using that name: ```python save_history(preset_name, current_state) ``` ### Technical Analysis `get_history_path()` interpolates `preset_name` directly into a filesystem path. It does not restrict path separators, traversal components such as `..`, absolute path syntax, or the final resolved location. The check that the supplied name exists in `presets.json` is not a sufficient security boundary. The project explicitly documents preset configuration as editable, and JSON object keys can contain path separators and ...[truncated 2138 chars]
Remediation
View remediation
None: if not PRESET_NAME_PATTERN.fullmatch(name): raise ValueError("Preset name contains unsupported characters") ``` 2. Resolve the generated path and verify that it remains beneath `RUNTIME_DIR`: ```python def get_history_path(preset_name: str) -> Path: validate_preset_name(preset_name) runtime_root = RUNTIME_DIR.resolve() path = (runtime_root / f"history_{preset_name}.json").resolve() if not path.is_relative_to(runtime_root): raise ValueError("History path escapes the runtime directory") return path ``` 3. For compatibility with Python versions lacking `Path.is_relative_to()`, use `relative_to()` and reject `ValueError`. 4. Consider deriving filenames from a safe identifier or a cryptographic hash rather than using configuration keys directly. 5. Reject absolute names, path separators, `.` and `..` components, control characters, and platform-specific separator variants. 6. Add tests for traversal payloads, including repeated `../`, backslashes on Windows, absolute paths, and encoded or unusual separator characters. 7. If concurrent execution is possible, write history atomically through a temporary file inside `runtime`, then replace the intended history file. ]]>

T08 · Insecure Dependencies

Warning
Location
tools/requirements.txt:1
Finding

Unpinned Third-Party Dependencies Create Supply-Chain Exposure

Content
View full analysis
=1.18 pandas ``` The documented installation process downloads and installs those dependencies at installation time: ```bash npx skills add alondotsh/alon-skills --skill fund-tracker ``` ```bash pip install -r tools/requirements.txt ``` ### Technical Analysis Neither Python package is pinned to a reviewed exact version, and no integrity hashes or lock file are supplied. `akshare>=1.18` accepts every future compatible version selected by the package resolver, while `pandas` has no version constraint at all. Consequently, two installations of the same audited project can execute different third-party code. A future compromised, malicious, or incompatible release may be selected without any change to this repository. Python package installation may execute build-system code, and imported dependencies execute with the same privileges as the fund-tracker process. The documented `npx` installation command also resolves and executes external package tooling. The documentation does not pin that tool to a reviewed version or describe an integrity-verification mechanism. No evidence was found that the currently named packages are malicious. The finding concerns unsafe dependency acquisition and the absence of reproducible integrity controls. ### Attack Path 1. A user follows the documented installation instructions. 2. `pip` queries the configured package index and resolves versions satisfying `akshare>=1.18` and the unconstrained `pandas` requirement. 3. A newly published, compromised, or dependency-confused package version is selected. 4. Package build or installation hooks may execute during installation. 5. The installed package is later impor ...[truncated 885 chars]
Remediation
View remediation
pandas== ``` 2. Generate a lock file that includes the complete transitive dependency graph. 3. Use hash verification, such as a `requirements.txt` generated with hashes, and install with: ```bash pip install --require-hashes -r requirements.txt ``` 4. Review and update pinned versions through a controlled dependency-update process with automated tests and security scanning. 5. Install from the expected trusted package index explicitly and disable unintended extra indexes where operationally possible. 6. Pin the package and version used by `npx`, or replace runtime package resolution with a reviewed installation mechanism. Use non-interactive controls such as `--ignore-scripts` only where compatible with the required package. 7. Avoid running dependency installation with administrator or root privileges. Use an isolated virtual environment or container with minimum filesystem and network permissions. 8. Add automated software-composition analysis and dependency-integrity checks to continuous integration. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

The README instructs users to install and execute a package via npx skills without pinning an exact version. This can cause users to run whatever version is currently published or resolved at install time, which introduces supply-chain risk if the package is updated maliciously, compromised, or changed incompatibly.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The README instructs users to install the skill via npx skills add ... without pinning a specific package or tool version. This creates a supply-chain risk: users may fetch a newer or compromised version of the installer or referenced package, leading to unexpected code execution during installation. In this skill context, the command is part of setup documentation, so the danger is real because users are likely to copy-paste it directly.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to read and modify local files (tools/presets.json and runtime/history_<name>.json) and execute a local Python script, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authority/visibility gap where the agent may perform file operations without a clearly bounded permission model, increasing the risk of unintended file access or modification if the preset name or update flow is abused.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest emphasizes using local AKShare-based tracker presets under the skill root to check fund availability, quota, fee, and changes. In practice, the implementation does not operate only on local preset data: it performs a fresh external data retrieval via ak.fund_purchase_em(), which is a material behavior beyond merely using local presets.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file is written in Chinese and presents the skill content in that language by default, while only linking to an English version. Under the policy rule for language/locale, this can be treated as forcing a specific language without explicit user opt-in inside the skill description itself.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes checking fund purchase availability, quotas, fees, and changes versus the previous run, but it does not disclose that the implementation achieves this by writing persistent history files under runtime/. This is a meaningful behavior difference because the skill is not purely read-only; it modifies local state on each run.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency 'akshare>=1.18' is only lower-bounded, so future installations may resolve to newer unreviewed versions with changed behavior or newly introduced vulnerabilities. For a finance-oriented skill that relies on external data tooling, this weakens supply-chain control even if the package choice itself appears legitimate.

Content

Scanner excerpt · tools/requirements.txt (reported line 1)May include surrounding context.

text
akshare>=1.18
pandas

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency 'pandas' is unpinned, so installs may pull different versions over time, reducing build reproducibility and potentially introducing a vulnerable or incompatible release without notice. In this skill, the package is a common data-processing library and there is no direct evidence of malicious intent, but version drift still creates supply-chain risk.

Content

Scanner excerpt · tools/requirements.txt (reported line 2)May include surrounding context.

text
akshare>=1.18
pandas

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
76% confidence
Finding

The manifest does not pin pandas, and pandas has at least one known advisory affecting some historical versions, so it is impossible to verify from this file whether deployment would select a safe release. The referenced issue is disputed and may require unsafe deserialization usage, which lowers severity, but the lack of version pinning still leaves exposure uncertain.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.