Back to skill

Security audit

trading-sop

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly coherent for A-share trading workflows, but its optional local dashboard exposes report contents through unsafe browser-facing APIs and Markdown rendering.

Review before installing or running the dashboard. The trading workflow itself is disclosed, but until the dashboard is hardened, only use it with report files you trust, keep it bound to localhost, stop it after use, and avoid exposing sensitive reports through the local web UI. Ask the publisher to remove wildcard CORS and sanitize or disable raw HTML in Markdown rendering.

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

Error
Location
web/index.html:1608
Finding

Stored Cross-Site Scripting in Markdown Report Rendering

Content
View full analysis

Vulnerability Details

File Location: web/index.html:1608-1609, with the unsafe parser at web/index.html:1716-1794
Vulnerability Type: Stored Cross-Site Scripting (XSS)
Risk Level: High

Vulnerable Code

javascript
// Render Markdown content
const mdSurface = document.getElementById('reportMarkdownBody');
mdSurface.innerHTML = parseAdvancedMarkdown(data.body_markdown || data.raw_content);

The report content is processed by a custom Markdown parser that does not escape raw HTML:

javascript
function parseAdvancedMarkdown(md) {
  if (!md) return '';
  let text = md;

  // 1. Code blocks with copy button
  text = text.replace(/```([a-zA-Z0-9_-]*)\n([\s\S]*?)```/gm, (match, lang, code) => {
    const escaped = escapeHtml(code);
    return `
      <div class="code-block-wrapper">
        <div class="code-block-header">
          <span>${lang || 'text'}</span>
          <button class="code-copy-btn" aria-label="复制代码块" onclick="copySnippet(this)" data-code="${encodeURIComponent(code)}">复制</button>
        </div>
        <pre><code class="lang-${lang}">${escaped}</code></pre>
      </div>
    `;
  });

  // 2. Callout Cards
  text = text.replace(/^\>\s+\[!(NOTE|TIP|WARNING|IMPORTANT|CAUTION)\]\s*\n((?:\>.*(?:\n|$))*)/gim, (m, type, body) => {
    const cleanBody = body.replace(/^\>\s?/gm, '').trim();
    const typeLower = type.toLowerCase();
    let icon = 'ℹ️';
    if (typeLower === 'tip') icon = '💡';
    else if (typeLower === 'warning') icon = '⚠️';
    else if (typeLower === 'important') icon = '⚡';
    else if (typeLower === 'caution') icon = '🛑';

    return `
      <div class="callout-card ${typeLower}">
        <div class="callout-header">
          <span>${icon}</span>
          <span>${type}</span>
        </div>
        <div>${parseInlineMarkdown(cleanBody)}</div>
      </div>
    `;
  });

  // 3. Regular Blockquotes
  text = text.replace(/^\>\s+(.*$)/gim, '<blockquote>$1</blockquote>');

  // 4. Headers
  text = text.repl
...[truncated 4086 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the custom Markdown implementation with a maintained renderer configured to disable raw HTML.
  2. Sanitize all generated HTML with a strict allowlist before assigning it to innerHTML.
  3. Remove event-handler attributes, scripts, dangerous URL schemes, embedded frames, and other active content.
  4. Prefer DOM construction and textContent for report metadata and other plain-text fields.
  5. Avoid inline event handlers in application-generated markup. Register handlers with addEventListener instead.
  6. Deploy a restrictive Content Security Policy that blocks inline scripts and event handlers as defense in depth.
  7. Add regression tests containing script elements, event-handler attributes, SVG-based payloads, malformed markup, and dangerous links.
  8. Treat every report as untrusted unless its provenance and integrity are explicitly verified.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/server.py:30
Finding

Unrestricted CORS Exposes Local Report APIs to Unrelated Websites

Content
View full analysis

Vulnerability Details

File Location: scripts/server.py:30-36
Vulnerability Type: Cross-Origin Information Disclosure
Risk Level: Medium

Vulnerable Code

python
def send_json(self, data: object, status: int = 200) -> None:
    body = json.dumps(data, ensure_ascii=False).encode("utf-8")
    self.send_response(status)
    self.send_header("Content-Type", "application/json; charset=utf-8")
    self.send_header("Content-Length", str(len(body)))
    self.send_header("Access-Control-Allow-Origin", "*")
    self.end_headers()
    self.wfile.write(body)

The affected JSON method serves both report-list and report-detail responses:

python
if path == "/api/reports":
    category = query.get("category", [None])[0]
    reports = scan_reports(self.report_dir)
    if category and category != "all":
        reports = [r for r in reports if r.get("category") == category]
    self.send_json(reports)
    return
python
if path == "/api/report":
    rel_path = query.get("path", [None])[0]
    if not rel_path:
        self.send_error_json("Missing 'path' parameter", 400)
        return
    detail = get_report_detail(self.report_dir, rel_path)
    if not detail:
        self.send_error_json(f"Report not found: {rel_path}", 404)
        return
    self.send_json(detail)
    return

Technical Analysis

The HTTP server allows every web origin to read its JSON responses by returning:

http
Access-Control-Allow-Origin: *

The service defaults to 127.0.0.1:19876, but loopback binding does not prevent a page loaded from an unrelated website from initiating browser requests to the local service. CORS normally prevents that unrelated page from reading the responses. The wildcard header explicitly removes that browser-enforced confidentiality boundary.

Neither /api/reports nor /api/report requires authentication. The former discloses relative report paths, and the latter returns complete report content for a supplied path constrain ...[truncated 1738 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove Access-Control-Allow-Origin: * from the default response path.
  2. For a same-origin dashboard, omit CORS headers entirely.
  3. If cross-origin integration is required, maintain an explicit allowlist of trusted origins and reject all other Origin values.
  4. Require a cryptographically random per-session token for report APIs and avoid placing long-lived secrets in URLs.
  5. Validate Host and Origin headers to reduce browser-based access from unrelated sites.
  6. Consider requiring explicit user activation before serving report contents.
  7. Keep loopback binding as defense in depth, but do not treat it as a replacement for authentication and origin validation.
  8. Add automated tests verifying that requests from arbitrary origins cannot read /api/reports or /api/report.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documentation includes running an HTTP server and exposing APIs, which is a materially different risk profile from a conversational trading SOP assistant. Exposing local report data and chart endpoints over HTTP can broaden access to sensitive workspace content or create an unintended local service surface that users did not knowingly approve.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documentation includes running an HTTP server and exposing APIs, which is a materially different risk profile from a conversational trading SOP assistant. Exposing local report data and chart endpoints over HTTP can broaden access to sensitive workspace content or create an unintended local service surface that users did not knowingly approve.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documentation includes running an HTTP server and exposing APIs, which is a materially different risk profile from a conversational trading SOP assistant. Exposing local report data and chart endpoints over HTTP can broaden access to sensitive workspace content or create an unintended local service surface that users did not knowingly approve.

Content

No source excerpt is available for this finding.

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

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

md
# User current working directory / workspace
        root / "market" / "data" / "market_raw.db",
        root / "data" / "market_raw.db",
        # Sibling directory (covers both repo root and ~/.gemini/config/skills/)
        skill_dir.parent / "market" / "data" / "market_raw.db",
        # Relative to parents of skill
        skill_dir.parent.parent / "market" / "data" / "market_raw.db",

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · scripts/market_reader.py (reported line 33)May include surrounding context.

python
# User current working directory / workspace
        root / "market" / "data" / "market_raw.db",
        root / "data" / "market_raw.db",
        # Sibling directory (covers both repo root and ~/.gemini/config/skills/)
        skill_dir.parent / "market" / "data" / "market_raw.db",
        # Relative to parents of skill
        skill_dir.parent.parent / "market" / "data" / "market_raw.db",

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says this skill should recognize trading intents such as pre-market prep, post-market review, deep stock research, and first-board overnight scenarios, then orchestrate existing skill pipelines to produce actionable recommendations. This file instead exposes web APIs and static dashboard content for reports, K-line data, and SVG chart rendering, with no natural-language intent recognition or SOP orchestration logic present.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · web/index.html (reported line 1102)May include surrounding context.

html
</head>
<body>

  <!-- =======================================================================
       Header Navigation Bar
       ======================================================================= -->
  <header role="banner">

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares executable capabilities such as environment access, file reads, and network-adjacent behavior without an explicit tool or permission scope. In an agent environment, missing scope boundaries increases the chance the skill can access data or resources beyond what users reasonably expect, especially since it also orchestrates other skills and writes files.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Very broad trigger phrases raise the risk of accidental invocation in ordinary conversation, which matters here because the skill can orchestrate other components, create files, and potentially start auxiliary services. Unexpected activation can lead to unintended data access, report generation, or trading-related recommendations without clear user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill specifies automatic report creation in the user's workspace without prominently warning users before files are written. Silent file creation is risky in agent systems because it can clutter repositories, overwrite expectations, or cause sensitive derived content to be stored where other tools or sync systems can access it.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Expanding an orchestration skill into a dashboard host and chart-rendering API increases attack surface beyond the stated advisory role. Even when bound locally, HTTP services can leak report contents, enable unintended file access patterns, or be abused by other local processes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The eval prompts use broad, ordinary trading-assistant phrasing such as '怎么操作', '复盘一下', and '完整分析', which can overlap with common user requests and cause the skill to activate without strong scoping. In an orchestration skill that can trigger multi-step analysis and decision pipelines, ambiguous activation increases the risk of unintended execution, user confusion, and generation of trading guidance in contexts where the user did not explicitly request the full SOP flow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

All prompts and expected outputs are written exclusively in Chinese and imply a fixed Chinese-language operating mode, but this file does not state that the skill is region-specific or that users can choose another language. That creates a potential language/locale policy issue under the requirement to avoid forcing a specific language without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file’s operational instructions, headings, and outputs are all specified only in Chinese, and there is no natural-language indication that users may choose another language or that the skill is intentionally limited to Chinese-speaking users. Under the language/locale policy rule, forcing a specific language without user opt-in is a policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file contains operational instructions exclusively in Chinese, and nowhere indicates that users may choose another language or that the skill is intentionally limited to a Chinese-speaking or region-specific audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The SOP authorizes simulated trade execution and creation of trade records/exit plans when the user explicitly requests it, but it does not require a prominent user-facing disclosure immediately before execution that records will be created and a T+1 exit plan generated. In a trading skill, this can mislead users about whether they are receiving analysis only or causing stateful portfolio-like artifacts to be created, increasing the risk of unintended actions and over-reliance on automation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Running a threaded HTTP server that serves static web assets and exposes browser-consumable APIs is a separate application capability from orchestrating analysis skills from user trading requests. Nothing in the manifest indicates this skill should host a dashboard or provide direct HTTP endpoints for report browsing and chart rendering.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The title, section headers, and descriptive text are all hard-coded in Chinese throughout the template. This creates a language/locale constraint in natural-language content without any visible mechanism for user selection or documented justification, which matches the policy-violation criterion for forced language usage.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document sets lang="zh-CN", and the visible UI strings throughout the page are Chinese-only. This forces a specific language/locale experience without any opt-in, selector, or documented regional justification, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Manifest 将该技能描述为从自然语言识别交易意图并编排调用既有技能,重点是 SOP 总编排与决策建议输出。但该页面代码直接实现了研报列表读取、单篇研报查看、K线/SVG图表加载和指标展示,形成了一个较完整的投研终端,而不仅是编排入口或结果展示层。

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The documentation says the skill 'does not generate any raw data' and only routes, invokes, and summarizes. Later sections require the skill to write SOP execution summaries into workspace report directories, which is additional persistent output behavior beyond a purely transient orchestration layer.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The chart title string explicitly labels output as "A-Share," which ties the feature to a specific regional market context in natural-language output. The file does not indicate that this locale/market framing is optional or user-selectable, so it may violate the policy against forcing a specific locale without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

按钮 aria-label 与文案写明“刷新所有研报”,容易让人理解为刷新整个看板或当前所有相关数据。实际 onclick 仅调用 refreshReports(),而该函数只请求 /api/reports 列表,不会刷新当前报告详情或行情/K线数据,因此文案与实现存在直接偏差。

Content

No source excerpt is available for this finding.