Back to skill

Security audit

cn-funds-mcp

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate China-market finance MCP server, but it needs review because it stores sensitive portfolio/reminder data and forces proactive reminder checks that can turn saved custom reminder text into agent-facing instructions.

Install only if you are comfortable with a finance MCP server storing your fund holdings and reminders locally and sending fund/stock identifiers to third-party market-data APIs. Review or disable the automatic reminder workflow before use, especially custom reminders, and avoid uploading unredacted brokerage or payment-app screenshots. Treat any add/reduce-position output as generic analysis, not regulated investment advice.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:86
Finding

Persistent Prompt Injection Through Custom Reminders

Content
View full analysis

Vulnerability Details

File Locations:

  • SKILL.md:86-88
  • src/portfolio.js:76-88
  • src/index.js:395-421

Vulnerability Type: Persistent user-controlled instruction injection
Risk Level: Critical

Vulnerable Code

src/portfolio.js:76-88 persists arbitrary reminder messages:

js
export function addReminder({ time, type = "profit_report", message = "" }) {
  const data = loadReminders();
  const id = `r_${Date.now()}`;
  data.reminders.push({
    id,
    time,
    type,
    message,
    enabled: true,
    createdAt: new Date().toISOString().slice(0, 10),
  });
  saveReminders(data);
  return data.reminders;
}

src/index.js:395-421 retrieves the stored message, places it in Agent-facing output, and directs the Agent to execute the resulting guidance:

js
server.tool(
  "check_reminders",
  "检查是否有到期的提醒(AI 应在每次对话开始时主动调用此工具)。返回当前到期未触发的提醒列表,同一提醒每天只触发一次。",
  {},
  async () => {
    const { due, today, currentTime, message } = portfolio.checkReminders();

    if (message) {
      return { content: [{ type: "text", text: message }] };
    }

    if (due.length === 0) {
      return { content: [{ type: "text", text: `当前时间 ${today} ${currentTime},没有到期的提醒。` }] };
    }

    const actions = due.map((r) => {
      if (r.type === "profit_report") {
        return `[${r.time}] 持仓收益播报 → 请立即调用 get_portfolio_profit 查询收益,并根据涨跌情况给出加仓/减仓建议`;
      }
      if (r.type === "market_report") {
        return `[${r.time}] 大盘播报 → 请调用 get_market_overview + get_market_capital_flow 播报大盘行情`;
      }
      return `[${r.time}] 自定义提醒: ${r.message}`;
    });

    return {
      content: [{
        type: "text",
        text: `当前时间 ${today} ${currentTime},有 ${due.length} 个提醒到期:\n\n${actions.join("\n\n")}\n\n请按照上述指引执行对应操作。`,
      }],
    };
  }
);

The corresponding Skill instructions in SKILL.md:86-88 require check_reminders to be invoked before responding in every conversation, regardless of the user's request.

Technical Analysis

The set_reminder ...[truncated 2221 chars]

Remediation
View remediation

Remediation Suggestions

  1. Treat every reminder message as untrusted display data, never as an operational instruction.
  2. Remove wording that directs the Agent to follow reminder content.
  3. Return structured reminder data instead of instruction-like prose, for example:
    json
    {
      "due": [
        {
          "type": "custom",
          "message": "Untrusted user-provided reminder text"
        }
      ]
    }
    
  4. Explicitly label custom messages as quoted user content that must not control tool use, policy, or Agent behavior.
  5. Do not require check_reminders before every unrelated user request. Invoke it only when the user asks about reminders, or perform a passive check that cannot initiate actions.
  6. Require explicit, current-session user confirmation before executing tools suggested by any reminder.
  7. Apply reasonable length and character limits to custom messages and validate the HH:MM time format.
  8. Separate reminders by authenticated user or session if the MCP server can be shared.
  9. Provide a mechanism to inspect and delete stored reminders before they are rendered to the Agent.
  10. Add tests using adversarial reminder text to verify that reminder content remains inert data.

T08 · Insecure Dependencies

Warning
Location
package.json:35
Finding

Unpinned Package Execution Through npx

Content
View full analysis

Vulnerability Details

File Location: package.json:35
Vulnerability Type: Unpinned executable development dependency
Risk Level: Medium

Vulnerable Code

json
"scripts": {
  "start": "node src/index.js",
  "inspect": "npx @modelcontextprotocol/inspector node src/index.js"
}

Technical Analysis

The inspect script invokes @modelcontextprotocol/inspector through npx, but the package is not declared at an exact reviewed version in dependencies or devDependencies. If no suitable local installation exists, npx may resolve and download package content from the configured registry at execution time.

Consequently, the code executed by npm run inspect can differ from the code present during this audit. This weakens build reproducibility and creates a supply-chain execution path. A compromised upstream release, registry account, registry configuration, or package resolution process could cause unaudited code to run locally.

The exposure is limited to users or automation that execute the optional inspect script; normal npm start execution does not invoke this command.

Attack Path

  1. A developer or automated environment runs npm run inspect.
  2. npx searches for the requested package and may resolve it from the configured package registry.
  3. Because no exact reviewed version is specified in the project, the resolved code may change over time.
  4. npx downloads or invokes the resolved package.
  5. Package code executes with the privileges of the user or automation account running the command.
  6. A compromised package version could access files, environment variables, network resources, or other assets available to that account.

Impact Assessment

Exploitation could execute arbitrary third-party code with the privileges of the user running the inspection command. Potential scope includes the project workspace, user-readable files, environment variables, and network access permitted to that process.

This findi ...[truncated 185 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a reviewed, exact version of @modelcontextprotocol/inspector to devDependencies.
  2. Avoid version ranges for executable development tooling where reproducibility is required.
  3. Generate and commit the package manager lockfile.
  4. Use npm ci in development and continuous-integration environments to enforce the locked dependency graph.
  5. Invoke the locally installed binary from the npm script rather than relying on an on-demand npx download:
    json
    {
      "devDependencies": {
        "@modelcontextprotocol/inspector": "REVIEWED_EXACT_VERSION"
      },
      "scripts": {
        "inspect": "mcp-inspector node src/index.js"
      }
    }
    
  6. Verify the actual binary name and reviewed version before applying the example.
  7. Review dependency provenance, integrity hashes, transitive dependencies, and lifecycle scripts.
  8. Run inspection tooling in a restricted environment without unnecessary secrets or filesystem permissions.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill description presents a market-data assistant, but the instructions also add reminder scheduling, forced per-conversation reminder checks, and automated investment suggestions. That behavioral expansion matters because it introduces persistent state, proactive execution, and financial decision support beyond simple data retrieval, which can surprise users and trigger actions they did not explicitly request.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description presents a market-data assistant, but the instructions also add reminder scheduling, forced per-conversation reminder checks, and automated investment suggestions. That behavioral expansion matters because it introduces persistent state, proactive execution, and financial decision support beyond simple data retrieval, which can surprise users and trigger actions they did not explicitly request.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill advertises and orchestrates numerous network-backed data tools but does not declare an explicit tool scope such as allowed-tools or permissions. This weakens least-privilege controls and makes it harder for the host to constrain what external capabilities the skill is expected to use, increasing the chance of overbroad or unintended tool access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger condition is extremely broad, matching common finance-related words such as stocks, profit, holdings, and market terms. This can cause accidental invocation in unrelated conversations, leading to unnecessary tool calls, unexpected access to stored portfolio/reminder data, and confusing or privacy-invasive behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The usage guide and operational instructions are written entirely in Chinese and direct the assistant's behavior in that locale without indicating that users may choose another language. This can violate language-choice policy when the skill is used in broader contexts where user language preference is not explicitly collected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The screenshot-import workflow encourages users to upload financial app screenshots containing highly sensitive data, but it does not present a privacy warning or minimization guidance first. Such screenshots may expose account balances, names, transaction history, device metadata, or other information beyond the fields needed for portfolio import, creating elevated privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill states that portfolio data is persisted across sessions in data/portfolio.json but does not require a user-facing warning or explicit consent. Because holdings, cost basis, and profit data are sensitive financial information, silent retention increases privacy risk and the chance users disclose data without understanding it will be stored long-term.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The inspect script invokes npx @modelcontextprotocol/inspector without pinning an exact version, so each execution may fetch whatever release is current at the time. That creates a supply-chain risk: a compromised, malicious, or simply breaking upstream release could be executed locally during development or review with the privileges of the user running the command.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The error message string "无法解析基金...的估值数据" is hardcoded in Chinese, which imposes a specific language choice on users. Under the language/locale policy, forcing a language without offering user choice or documenting a justified locale constraint is a policy violation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · src/api.js (reported line 259)May include surrounding context.

js
}

export async function getSectorCapitalFlow(timeType = "f62", code = "m:90+s:4") {
  const url = `https://data.eastmoney.com/dataapi/bkzj/getbkzj?key=${timeType}&code=${encodeURIComponent(code)}`;
  const data = await fetchJSON(url);
  if (!data.data?.diff) return [];
  return data.data.diff.map((d) => ({

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The portfolio save/remove tools persistently modify user holdings records, but the code provides no explicit warning that data is being stored locally or deleted from local state. This can violate user expectations around data retention and creates privacy/integrity risk if sensitive financial positions are stored without clear consent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill introduces reminder/scheduling capabilities that are not reflected in the declared skill scope, expanding behavior from data retrieval and portfolio tracking into persistent, time-triggered actions. This scope drift matters because users and orchestrators may not expect background-style behavioral state, which can lead to surprising autonomous actions and trust boundary violations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Reminder creation and deletion modify persisted user configuration, yet there is no explicit disclosure that reminder settings are stored and retained. Because reminders may encode behavioral schedules and custom messages, silent persistence increases privacy risk and can cause confusing future assistant behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language instruction text and generated reminder actions are written to steer the agent toward Chinese-language output and behavior, without any opt-in or alternative locale handling. This can violate language/locale policy when users have not chosen Chinese as their preferred language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code directs the AI to provide '加仓/减仓建议' after querying portfolio profit, which expands the skill from market data/portfolio calculation into investment advice. In a financial context, undisclosed advisory behavior is risky because it can influence user trading decisions without explicit authorization, suitability checks, or clear disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes a China fund/stock data assistant that queries market data and manages a user's fund portfolio with profit calculation. This file additionally implements persistent reminder creation, deletion, toggling, and due-checking logic, which is a distinct feature not mentioned in the manifest description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The clearPortfolio function overwrites the portfolio data with an empty list, which is an irreversible data-destructive operation within this skill. The file contains no confirmation prompt, logging, comment, or other user disclosure around this action.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

Most of the operational tool descriptions and usage details are provided only in Chinese, with no statement that the user can choose another language. This can violate a language/locale policy when a skill effectively forces one language for core instructions without opt-in or an explicit region-specific justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The README states that portfolio holdings are saved to data/portfolio.json, which means the skill persists user financial holdings data locally. While the file location is disclosed, there is no explicit warning that sensitive personal investment data will be stored on disk or guidance about protecting/removing it.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The description explicitly frames the skill as a China fund and stock data server and presents bilingual Chinese-focused wording, which indicates a locale-specific scope. In a manifest file, this can be a natural-language policy concern if the skill implicitly constrains language/locale behavior without stating user choice or opt-in.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The dependency @modelcontextprotocol/sdk is specified with a caret range, allowing different installed versions over time. While common in JavaScript projects, this weakens build reproducibility and can silently introduce vulnerable or malicious upstream changes into a server that processes user financial queries and portfolio data.

Content

Scanner excerpt · package.json (reported line 38)May include surrounding context.

json
"inspect": "npx @modelcontextprotocol/inspector node src/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1"
  }
}

Unverifiable Dependency: @modelcontextprotocol/sdk has 3 known advisory(ies) (CVE-2026-25536 (@modelcontextprotocol/sdk has cross-client data leak via shared server/transport); CVE-2026-0621 (Anthropic's MCP TypeScript SDK has a ReDoS vulnerability); CVE-2025-66414 (Model Context Protocol (MCP) TypeScript SDK does not enable DNS rebinding protec)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding

The manifest references @modelcontextprotocol/sdk without pinning, and the package family has known advisories including cross-client data leakage, ReDoS, and missing DNS rebinding protections. Because the exact installed version is not fixed, it is impossible to verify from this manifest alone whether deployments are protected, which is especially relevant for an MCP server that may handle user portfolio and market-query context across clients.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code transmits user-provided query data such as fund search keywords and fund codes to third-party Eastmoney/1234567 endpoints, but the file contains no print/log statement, confirmation, or explanatory comment/docstring disclosing that external network transmission occurs. Because the file is a code file, outbound requests involving user data should have some visible disclosure unless clearly documented elsewhere.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code includes Chinese-language comments and a returned user-facing message (今天是周末,A股休市。) without offering any language choice. This can violate language/locale policy when a skill forces a specific language for user-visible output without explicit opt-in or documented regional scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.