neotty/mcp-client-browser
criticalTypeScript SDK for using large language models with an MCP server directly in the browser, powered by Cherry Studio's prompt templates.
MCP server (purpose undetermined)
14constructor(
15 mcpUrls: (URL | { url: URL, headers?: Record<string, string>, name?: string }) | (URL | { url: URL, headers?: Record<string, string>, name?: string })[],
16 openAIConfig?: {
17 baseUrl?: string,
18 apiKey?: string,
19 model?: string,
20 }
21) {
22 const urlConfigArray = Array.isArray(mcpUrls) ? mcpUrls : [mcpUrls];
23 this.mcpConnections = urlConfigArray.map((item, index) => {
24 if (item instanceof URL) {
25 return {
26 url: item,
27 client: new Client({
28 name: `sse-client-${index}`,
29 version: '1.0.0'
30 }),
31 name: item.hostname
32 };
33 } else {
34 return {
35 url: item.url,
36 headers: item.headers || {},
37 client: new Client({
38 name: `sse-client-${index}`,
39 version: '1.0.0'
40 }),
41 name: item.name || item.url.hostname
42 };
43 }
44 });
45}// Exploitable if an attacker can influence the mcpUrls parameter (e.g., via prompt injection or configuration manipulation).
The MCP client accepts arbitrary URLs for SSE connections without any validation or allowlisting. An attacker who can control the input (e.g., via prompt injection or configuration) can make the client connect to any external server, potentially exfiltrating data or performing SSRF attacks.
ImpactAn attacker could redirect the MCP client to a malicious SSE server, exfiltrate sensitive data (e.g., API keys, chat history), or perform SSRF attacks against internal services.
FixImplement a whitelist of allowed SSE server URLs or validate URLs against a known pattern. Restrict connections to trusted servers only.
55if (openAIConfig?.baseUrl && (openAIConfig?.apiKey !== undefined)) {
56 this.openAI = new OpenAI({
57 apiKey: openAIConfig.apiKey || '', // 允许空字符串
58 baseURL: openAIConfig.baseUrl,
59 dangerouslyAllowBrowser: true
60 });
61 this.openAI.apiModel = openAIConfig.model || "gpt-3.5-turbo";
62}// Exploitable if an attacker can read process memory or if the client runs in a browser environment where secrets are exposed.
The OpenAI API key is passed in plaintext to the constructor and stored in memory. If an attacker gains access to the process memory or can exploit a vulnerability to read memory, the API key could be compromised. Additionally, the key is used in browser context with dangerouslyAllowBrowser: true, which exposes it to client-side attacks.
ImpactAn attacker could extract the OpenAI API key and use it to make unauthorized API calls, incurring costs or accessing sensitive data.
FixAvoid storing API keys in client-side code. Use a backend proxy to handle API calls, or use environment variables and server-side authentication. Remove dangerouslyAllowBrowser: true.
148async processQuery(
149 userSystemPrompt: string,
150 query: string,
151 useHistory: boolean = true,
152 maxTokens?: number,
153 topP?: number,
154 temperature?: number
155): Promise<string> {
156 if (!this.openAI) {
157 throw new Error("OpenAI API key not provided. Cannot process query.");
158 }
159 userSystemPrompt = userSystemPrompt || "";
160 const response = await this.listTools();
161 const systemPrompt = BuildSystemPrompt(userSystemPrompt, response.tools as unknown as MCPTool[]);
162 let messages: MessageContent[];
163 if (!useHistory || this.chatHistory.length === 0) {
164 messages = [
165 { role: "system", content: systemPrompt },
166 { role: "user", content: query }
167 ];
168 } else {
169 messages = [...this.chatHistory];
170 if (messages.length > 0 && messages[0].role === "system") {
171 messages[0].content = systemPrompt;
172 } else {
173 messages.unshift({ role: "system", content: systemPrompt });
174 }
175 messages.push({ role: "user", content: query });
176 }// Exploitable if an attacker can control the userSystemPrompt or query parameters (e.g., via a web interface or API).
The user-supplied system prompt and query are passed directly to the LLM without any sanitization or filtering. An attacker could inject malicious instructions that override the system prompt or manipulate the LLM to perform unintended actions, such as calling tools in unexpected ways.
ImpactAn attacker could perform prompt injection attacks to manipulate the LLM's behavior, potentially leading to unauthorized tool calls, data exfiltration, or other malicious actions.
FixSanitize and validate user inputs before passing them to the LLM. Use a separate, immutable system prompt that cannot be overridden. Implement input filtering to block known injection patterns.
252const result = await clientForTool.callTool({
253 name: toolName,
254 arguments: toolArgs
255});// Exploitable if the external MCP server is untrusted or compromised, or if an attacker can influence tool selection via prompt injection.
The tool arguments (toolArgs) are passed directly to the external MCP server without any validation or sanitization. If the external server is malicious or compromised, it could execute arbitrary commands or return malicious data. Additionally, if the tool name is manipulated, it could call unintended tools.
ImpactAn attacker could inject malicious arguments that cause the external MCP server to perform unintended actions, such as executing shell commands or reading sensitive files.
FixValidate tool names against a known list. Sanitize and validate arguments before passing them to external servers. Consider using a schema validation library.