Back to skill

Security audit

Finance Cron

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but its calendar sync API contains an unsafe shell-command path that could become local command execution if called with untrusted input.

Review this skill before installing in a shared or high-trust environment. Use the normal /finance-cron sync command only with fixed US, CN, or HK market values, avoid exposing the exported sync API to untrusted input, and inspect any generated /loop command before running it because it includes the command text you provided.

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

Error
Location
src/sync.ts:39
Finding
Shell Command Injection in the Exported Calendar Synchronization API## Vulnerability Details **File Location**: `src/sync.ts`, lines 39-42 **Vulnerability Type**: OS command injection through unsafe shell interpolation **Risk Level**: High ### Vulnerable Code ```typescript const { stdout, stderr } = await execAsync( `python3 "${scriptPath}" --market ${market}`, { timeout: 60000 } ); ``` ### Technical Analysis `CalendarSyncer.syncMarket()` constructs a shell command by directly interpolating `market` into a string passed to `child_process.exec()`. The `exec()` API invokes a shell, so shell metacharacters contained in the value are interpreted as command syntax rather than as part of a literal argument. Although `market` has the compile-time TypeScript type `Market`, TypeScript types are erased at runtime. The `CalendarSyncer` class and singleton are publicly exported, and `syncMarket()` does not independently validate its argument. The command-level handler validates market values before calling this method, but direct API consumers can bypass that handler. The constructor-controlled `scriptsPath` is also interpolated into the shell command. Quoting the path is insufficient protection if an untrusted caller can instantiate `CalendarSyncer` with a path containing quote characters or shell syntax. ### Attack Path 1. An application exposes or otherwise invokes the exported `calendarSyncer.syncMarket()` method using an attacker-controlled value. 2. The attacker supplies a runtime string containing shell metacharacters instead of one of the expected market identifiers. 3. `syncMarket()` inserts that value into the command string without runtime validation or shell escaping. 4. `execAsync()` passes the assembled string to the operating-system shell. 5. The shell interprets the injected syntax and executes an additional attacker-selected command. The normal `/finance-cron sync` handler validates values and is not, by itself, a demonstrated injection entry point. Exploitation applies ...[truncated 704 chars]
Remediation
## Remediation Suggestions 1. Replace `exec()` with `execFile()` or `spawn()` and pass arguments as a separate array so no shell parses the values: ```typescript import { execFile } from 'child_process'; import { promisify } from 'util'; const execFileAsync = promisify(execFile); const allowedMarkets: readonly Market[] = ['US', 'CN', 'HK']; async syncMarket(market: Market): Promise<SyncResult> { if (!allowedMarkets.includes(market)) { throw new Error('Invalid market'); } const scriptPath = path.resolve(this.scriptsPath, 'sync_calendars.py'); const { stdout, stderr } = await execFileAsync( 'python3', [scriptPath, '--market', market], { timeout: 60000 } ); // Continue processing the result. } ``` 2. Perform runtime allowlist validation inside `syncMarket()` itself, even if callers are also expected to validate input. 3. Resolve the script path to a canonical absolute path and verify that it remains within the expected bundled scripts directory. 4. Avoid accepting a caller-controlled scripts directory unless this configurability is required. If required, validate it before use. 5. Add negative tests using shell metacharacters, quotes, command substitutions, and invalid market names to verify that they cannot alter process execution.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:4
Finding
Unpinned Python Dependencies Allow Unreviewed Supply-Chain Changes## Vulnerability Details **File Location**: `requirements.txt`, lines 4-6 **Vulnerability Type**: Mutable third-party dependency resolution without integrity pinning **Risk Level**: Medium ### Vulnerable Code ```text pandas-market-calendars>=4.1.0 exchange-calendars>=4.2.0 chinese-calendar>=2.0.0 ``` The associated installation guidance in `README.md`, line 124, is: ```bash pip install pandas-market-calendars exchange-calendars chinese-calendar ``` ### Technical Analysis All Python dependencies use open-ended minimum versions, and the documentation installs the latest versions without a lock file or cryptographic hash verification. Consequently, two installations performed at different times can resolve materially different dependency graphs. Installing Python packages can execute package build and installation logic. If an upstream package account, release process, distribution artifact, or transitive dependency is compromised, following the documented installation procedure could introduce attacker-controlled code. Even without malicious compromise, an unreviewed future release could change trading-calendar behavior or compatibility. This is a supply-chain hardening weakness rather than evidence that the currently named packages are malicious. The npm dependency set has an integrity-bearing lock file, but no equivalent reproducible and hash-verified Python dependency set is provided. ### Attack Path 1. A user follows the project instructions or installs `requirements.txt`. 2. `pip` resolves the newest versions satisfying the open-ended minimum constraints, including their transitive dependencies. 3. A compromised or unexpectedly modified future package version is selected because no exact version or artifact hash is enforced. 4. Package installation or subsequent calendar synchronization imports and executes the selected package code. 5. The malicious or defective dependency operates with the per ...[truncated 740 chars]
Remediation
## Remediation Suggestions 1. Generate and commit a reviewed Python lock file containing exact direct and transitive dependency versions. 2. Require cryptographic hashes for every permitted artifact, for example by using `pip-compile --generate-hashes` and installing with `pip install --require-hashes`. 3. Update the README so users install from the locked, hash-verified manifest rather than installing unconstrained package names. 4. Perform dependency updates through a controlled review process that includes changelog review, vulnerability scanning, and calendar-output regression testing. 5. Install dependencies in a dedicated virtual environment or container with minimal filesystem and network permissions. 6. Use only the canonical package index or an organization-controlled mirror, and explicitly configure the trusted source to reduce dependency-confusion exposure.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (19)

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The documentation explicitly says the skill does not execute scheduled tasks by itself, framing it as a planning and calendar utility only. Later, the API usage section presents an `executeCommand` function with a comment 'Execute command', which directly suggests command execution capability and contradicts the earlier limitation.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The skill claims it does not directly execute tasks, but it generates a ready-to-run `/loop` command that interpolates the user-supplied `command` verbatim into `&& ${args.command}`. This meaningfully lowers the barrier to arbitrary command execution and can enable command/argument injection if operators copy-paste the generated string without scrutiny.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The `add` flow stores arbitrary commands and returns operational guidance for scheduled execution, but provides no explicit security warning that the command content may be dangerous. In this skill context, that omission is relevant because the feature is specifically designed to make later automated execution easy, increasing the chance that unsafe commands are scheduled and run.

Natural-Language Policy Violations

Medium
Confidence
81% confidence
Finding
This file contains natural-language comments and user-relevant descriptive text in Chinese throughout, such as the class and method descriptions. Under the policy rule, forcing a specific language without opt-in or justification can be a locale-policy violation, and this file does not document any language choice or region-specific requirement.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The markdown states that the skill can 'Sync latest holiday data from data sources,' which implies external data retrieval, but it does not disclose any network access or data update behavior to the user. For markdown files, the skill description should warn about behaviors that may affect privacy or system integrity, even if the risk here appears limited.

Known Vulnerable Dependency: yaml==2.8.2 — 1 advisory(ies): CVE-2026-33532 (yaml is vulnerable to Stack Overflow via deeply nested YAML collections)

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The lockfile pins yaml to version 2.8.2, and the provided advisory states this version is vulnerable to stack overflow when parsing deeply nested YAML collections. If this skill processes attacker-controlled YAML, an adversary could trigger denial of service by causing the process to crash or exhaust the call stack. The package-lock context alone does not prove exploitability, but it does confirm the vulnerable version is present.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"schedule"
  ],
  "dependencies": {
    "date-fns": "^3.6.0",
    "yaml": "^2.4.0"
  },
  "devDependencies": {
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
],
  "dependencies": {
    "date-fns": "^3.6.0",
    "yaml": "^2.4.0"
  },
  "devDependencies": {
    "@types/node": "^20.11.0",
Confidence
93% confidence
Finding
The yaml dependency is specified with a non-pinned range and the analysis indicates resolution to yaml 2.8.2, which has a known stack overflow vulnerability when parsing deeply nested YAML collections. In a skill that likely consumes calendar/config data, malformed YAML from an untrusted or synced source could trigger denial of service through parser exhaustion or crash.

Known Vulnerable Dependency: yaml==2.8.2 — 1 advisory(ies): CVE-2026-33532 (yaml is vulnerable to Stack Overflow via deeply nested YAML collections)

Low
Category
Supply Chain
Confidence
98% confidence
Finding
The package resolves to yaml 2.8.2, which is flagged as vulnerable to stack overflow via deeply nested YAML collections. Because this skill appears to work with calendars and includes a script to sync calendar data, YAML parsing may be part of normal operation, making denial-of-service through maliciously crafted input more plausible than in a package that never parses external data.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"yaml": "^2.4.0"
  },
  "devDependencies": {
    "@types/node": "^20.11.0",
    "typescript": "^5.3.0"
  },
  "engines": {
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "devDependencies": {
    "@types/node": "^20.11.0",
    "typescript": "^5.3.0"
  },
  "engines": {
    "node": ">=18.0.0"
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# Python dependencies for trading calendar sync
# Install with: pip install -r requirements.txt

pandas-market-calendars>=4.1.0
exchange-calendars>=4.2.0
chinese-calendar>=2.0.0
Confidence
92% confidence
Finding
The dependency is specified with only a minimum version, so future installs may resolve to newer, unreviewed releases. This creates a supply-chain and reproducibility risk because a compromised or breaking upstream release could be pulled into the environment without any code change in this repository.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# Install with: pip install -r requirements.txt

pandas-market-calendars>=4.1.0
exchange-calendars>=4.2.0
chinese-calendar>=2.0.0
Confidence
92% confidence
Finding
Using a >= constraint allows installation of any later version of the package, including releases that have not been security-reviewed or compatibility-tested for this skill. If the upstream package or one of its releases is malicious or vulnerable, deployments could silently consume it.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas-market-calendars>=4.1.0
exchange-calendars>=4.2.0
chinese-calendar>=2.0.0
Confidence
91% confidence
Finding
An unpinned dependency permits non-deterministic installs and increases exposure to dependency confusion, compromised upstream releases, or accidental breaking changes. In a requirements file, this is a genuine but low-severity supply-chain hygiene issue rather than an immediate exploitable flaw in application logic.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
The file's user-facing natural-language comments and method documentation are written entirely in Chinese, with no indication that language is selectable or intentionally limited to a Chinese-only audience. Under the stated policy, forcing a specific language without user opt-in can be a locale/language policy concern.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The updateCalendar method modifies persisted calendar data by calling fs.writeFileSync, but there is no confirmation prompt, user-facing log, or warning associated with this write operation. Because this changes local files, users may not realize the skill mutates on-disk state when invoking this method.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Multiple docstrings and usage descriptions are written in Chinese with no indication that users can choose another language. This creates a language policy concern because the skill appears to force one locale rather than offering or negotiating language preference.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
This TypeScript file contains natural-language comments and descriptions predominantly in Chinese, including user-relevant documentation for types and fields. Under the policy criteria, forcing a specific language without user choice or explicit justification can be a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
This file contains natural-language text in Chinese doc comments (for example L005-L006, L012-L013, L024-L025) and English user-facing return strings in L075-L079. Because the skill text does not indicate a user language preference, opt-in, or justified locale restriction, it may violate the language/locale policy requiring choice or documentation.

Static analysis

No suspicious patterns detected.