Back to skill

Security audit

Kerrystock

Security checks for vulnerabilities and agentic risk

Overview

Kerrystock is a disclosed financial-analysis workflow skill, with some implementation risks users should understand before running it.

Install only if you are comfortable running local finance-analysis scripts that call external tools and create report files. Use temporary NeoData tokens carefully because the documented flow passes them on the command line, run the skill in a trusted shell, avoid untrusted NODE_BIN/PYTHON_BIN or script-path environment overrides, and do not generate or share HTML reports from untrusted names, codes, or JSON inputs without escaping/sanitizing them.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gen_report.py:82
Finding

HTML and JavaScript Injection in Generated Reports

Content
View full analysis
str: months = list(range(1, 13)) mean = [round(stats["monthly"][str(m)]["mean"] * 100, 2) for m in months] win = [round(stats["monthly"][str(m)]["win_rate"] * 100, 1) for m in months] n = [stats["monthly"][str(m)]["n"] for m in months] bull = stats["bull"] bear = stats["bear"] years = sorted(int(y) for y in stats["yearly"].keys()) yret = [round(stats["yearly"][str(y)] * 100, 2) for y in years] last = tech["close"] peak = stats["peak"] peak_date = stats["peak_date"] from_peak = round((last / peak - 1) * 100, 1) trough = stats["trough"] trough_date = stats["trough_date"] cal = [1 if m in bull else (-1 if m in bear else 0) for m in months] bull_tag = " ".join(f'{m}月' for m in bull) or "—" bear_tag = " ".join(f'{m}月' for m in bear) or "—" html = f""" {name}({code}) 日历效应与买卖点策略 ``` Additional affected output contexts include direct interpolation into the report heading and body: ```python

{name} ({code}) 日历效应与买卖点策略

``` The values originate from command-line arguments without validation or escaping: ```python html = build_html(stats, tech, args.name, args.code, args.label) ``` ### Technical Analysis The report generator directly interpolates `name`, `code`, and `price_label` into an HTML document. It does not apply HTML escaping or context-aware output encoding. Ot ...[truncated 1984 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/neodata_verify.py:27
Finding

Temporary Access Token Exposed Through Process Arguments

Content
View full analysis
`, potentially placing the token in shell history. 3. The script launches the downstream NeoData process with the same token in its argument vector. 4. A local process, monitoring a ...[truncated 924 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的是一个完整的端到端投资分析/选股技能,核心输出应是季节性规律、交易信号、买卖策略和筛选结果。而代码块只执行基础行情数据获取与导出:规范化证券代码、按约两年分段拉取 westock-data K线、解析 markdown 表格、清洗去重并保存 CSV。它没有体现任何季节性统计分析、技术指标结合、策略生成、止盈止损/失效条件判断或选股流程。虽然使用了 westock-data,可能是整体工作流中的一个前置步骤,但就该代码块本身而言,其实际行为与声明的主要用途明显不符,属于功能范围显著缩水且主目的不同的描述-行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description presents a broad orchestrated skill that chains multiple systems for seasonal analysis, strategy construction, and stock screening. The supplied code chunk does not implement that workflow. Instead, it only wraps the neodata financial search tool for cross-verification by passing through a query and token, then optionally writing results to a markdown file. While neodata cross-validation is mentioned in the declared purpose as one component, this code alone is materially narrower than the claimed skill behavior and lacks the core analysis, timing, strategy, and screening steps. Therefore the code chunk does not accurately represent the declared end-to-end purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

The code is related to seasonality analysis, so it partially aligns with the description’s domain. However, the declared purpose emphasizes an end-to-end workflow that chains multiple external skills/services and produces buy/sell timing plus trade-plan outputs and screening. This code chunk only performs one internal analysis step: calculating historical monthly/yearly seasonality from a CSV and feeding derived bullish/bearish months into SignalEngine. It neither fetches data from the named tools nor implements the downstream trade-plan framework or stock screening. Therefore the description materially overstates the behavior of this specific code chunk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documents shell execution, environment-variable use, and reading/writing local files, but it declares no explicit tool scope or permission boundaries. That creates an overprivileged execution surface: if the skill is invoked in a permissive runtime, it may access files, tokens, or shell capabilities beyond what users and reviewers expect.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes an analytics workflow for calendar/seasonal stock and ETF analysis using listed data tools, but this lessons file adds an operational dependency on acquiring cloud-service tokens via connect_cloud_service and supplying them to neodata_verify.py. Handling external service credentials is not obviously required by the user-facing purpose and expands the skill’s operational capability beyond pure analysis intent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script permits both the Node binary and the target JavaScript file path to be overridden via environment variables, creating an unsafe execution boundary not required by the user-facing analytics purpose. An attacker who can set NODE_BIN or WESTOCK_DATA_SCRIPT can redirect execution to arbitrary code, leading to full code execution and potentially data exfiltration or persistence.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/export_kline.py (reported line 73)May include surrounding context.

python
def export(code: str, start: str, end: str, period: str, out: str) -> pd.DataFrame:
    frames = []
    for s, e in _segments(start, end):
        outp = subprocess.run(
            [NODE, WESTOCK, "kline", code, "--period", period,
             "--start", s, "--end", e, "--fq", "qfq"],
            capture_output=True, text=True,

Tainted flow: 'NODE' from os.environ.get (line 37, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
90% confidence
Finding

The executable path (NODE) is sourced from an environment variable and then executed. If an attacker can influence the process environment, they can cause this script to run an arbitrary binary instead of the expected managed Node runtime, resulting in arbitrary code execution under the script's privileges.

Content

Scanner excerpt · scripts/export_kline.py (reported line 73)May include surrounding context.

python
def export(code: str, start: str, end: str, period: str, out: str) -> pd.DataFrame:
    frames = []
    for s, e in _segments(start, end):
        outp = subprocess.run(
            [NODE, WESTOCK, "kline", code, "--period", period,
             "--start", s, "--end", e, "--fq", "qfq"],
            capture_output=True, text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The generated HTML loads ECharts from a third-party CDN at runtime, creating a supply-chain and privacy risk: whoever serves that script can execute arbitrary JavaScript in the context of the opened report. Because the report also embeds unescaped user-controlled values into the HTML, the external dependency increases the blast radius if the CDN is compromised or blocked, and it may leak access metadata when the report is viewed.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/neodata_verify.py (reported line 39)May include surrounding context.

python
# 关键:用 --token 直传,避免 --save-token 在只读环境的写入失败
    cmd = [PY, NEODATA, "--query", args.query, "--token", args.token]
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        sys.stderr.write(r.stderr)
        sys.exit(r.returncode)

Tainted flow: 'cmd' from os.environ.get (line 38, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
86% confidence
Finding

The command executed by subprocess.run incorporates PYTHON_BIN and NEODATA_SCRIPT from environment variables without validation. An attacker who can influence the environment can redirect execution to an arbitrary binary or script, causing unintended code execution and potentially exposing the supplied token or other process data.

Content

Scanner excerpt · scripts/neodata_verify.py (reported line 39)May include surrounding context.

python
# 关键:用 --token 直传,避免 --save-token 在只读环境的写入失败
    cmd = [PY, NEODATA, "--query", args.query, "--token", args.token]
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        sys.stderr.write(r.stderr)
        sys.exit(r.returncode)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The section titled '中国配色规范(强制)' mandates Chinese market color semantics and says charts and signals must follow them universally. This is a natural-language locale policy constraint, but the file does not present it as optional or limited to a China-specific reporting context chosen by the user.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The manifest describes an end-to-end seasonal analysis and strategy workflow that chains data/analysis skills, but this file's concrete behavior includes persisting fetched K-line data to an arbitrary local CSV path via to_csv. While exporting intermediate data may support the workflow, local file generation is not mentioned in the manifest description and is an observable behavior beyond pure analysis/orchestration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The generated HTML hardcodes lang="zh-CN", and the surrounding report text is entirely Chinese, indicating the skill enforces a specific language/locale. The file does not offer an opt-in or alternative locale selection, and no region-specific justification is documented in the code comments or interface.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language instructions and output text entirely in Chinese, including the top-level usage documentation and several user-facing status/error messages. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy concern unless the tool is clearly documented as region-specific, which is not stated here.

Content

No source excerpt is available for this finding.