Movin-T/mcp_basic_typescript
criticalModelContextProtocol Server and Client project using the Typescript SDK
This MCP server provides a test interface for managing user data, including reading all users or a specific user's profile from a local JSON file, cre...
126 const res = await server.server.request(
127 {
128 method: 'sampling/createMessage',
129 params: {
130 messages: [
131 {
132 role: 'user',
133 content: {
134 type: 'text',
135 text: 'Generate fake user data. The user should have a realistic name, email, address, and phone number. Return this data as a JSON object with no other text or formatter so it can be used with JSON.parse.',
136 },
137 },
138 ],
139 maxTokens: 1024,
140 },
141 },
142 CreateMessageResultSchema
143 );// Local-only MCP, requires compromised LLM or prompt injection from another tool to exploit.
The create-random-user tool sends a fixed prompt to the LLM via sampling/createMessage. If an attacker can control the LLM's behavior (e.g., through a compromised model or prompt injection in another tool), the LLM could return malicious JSON that, when parsed and passed to createUser, could lead to arbitrary data being written to the users.json file. Additionally, the prompt itself is hardcoded and does not sanitize any user input, but the vulnerability is that the LLM output is trusted and directly used.
ImpactAn attacker who can influence the LLM's output (e.g., via prompt injection in another tool or compromised model) could inject arbitrary user data into the database, potentially overwriting or corrupting existing data. Since the tool is local-only, exploitation requires a compromised LLM or prompt injection from another tool.
FixValidate the LLM output against a strict schema before using it. Ensure that the generated JSON contains only expected fields (name, email, address, phone) and that values are sanitized. Consider using a whitelist of allowed characters or types.
85server.tool(
86 'create-user',
87 'Create a new user in the database',
88 {
89 name: z.string(),
90 email: z.string().email(),
91 address: z.string(),
92 phone: z.string(),
93 },
94 ...
95 async (params) => {
96 try {
97 const id = await createUser(params);
98 return {
99 content: [{ type: 'text', text: `User ${id} created successfully` }],
100 };
101 } catch {
102 return {
103 content: [{ type: 'text', text: 'Failed to save user' }],
104 };
105 }
106 }
107);// Local-only MCP, exploitation requires attacker to send crafted prompts to the tool.
The create-user tool accepts name, address, and phone as plain strings with no length or content restrictions. While email is validated with z.string().email(), the other fields are not sanitized. This could allow injection of special characters or excessively long strings that might cause issues when written to the JSON file or when read by other tools.
ImpactAn attacker could provide malicious input (e.g., very long strings, special characters) that could corrupt the JSON file or cause parsing errors in other tools that read the file. However, since the data is only stored in a local JSON file and not executed, the impact is limited to data corruption or denial of service.
FixAdd length limits and sanitization for name, address, and phone fields. Use zod schemas with .max() and .regex() to restrict input to safe characters.
172server.prompt(
173 'generate-fake-user',
174 'Generate a fake user based on a given name',
175 {
176 name: z.string(),
177 },
178 ({ name }) => {
179 return {
180 messages: [
181 {
182 role: 'user',
183 content: {
184 type: 'text',
185 text: `Generate a fake user with the name ${name}. The user should have a realisting email, address, and phone number.`,
186 },
187 },
188 ],
189 };
190 }
191);// Local-only MCP, requires compromised LLM to exploit
The generate-fake-user prompt directly interpolates user input (the name parameter) into the LLM prompt without sanitization. An attacker could inject additional instructions into the prompt, potentially causing the LLM to generate malicious or unintended output.
ImpactA compromised LLM or an attacker controlling the prompt input could manipulate the LLM to generate arbitrary content, which could be used for social engineering or to produce harmful responses. However, since this is a prompt that returns messages to the client, the impact is limited to the LLM output.
FixSanitize or escape user input before interpolating into the prompt. Consider using a template that does not allow arbitrary injection, or validate the input to ensure it only contains expected characters.
126const res = await server.server.request(
127 {
128 method: 'sampling/createMessage',
129 params: {
130 messages: [
131 {
132 role: 'user',
133 content: {
134 type: 'text',
135 text: 'Generate fake user data. The user should have a realistic name, email, address, and phone number. Return this data as a JSON object with no other text or formatter so it can be used with JSON.parse.',
136 },
137 },
138 ],
139 maxTokens: 1024,
140 },
141 },
142 CreateMessageResultSchema
143 );// Local-only MCP, requires compromised LLM to exploit
The create-random-user tool uses LLM sampling to generate fake user data. The prompt is hardcoded and does not incorporate any user input, so direct prompt injection is not possible. However, the tool relies on the LLM to produce valid JSON, and a compromised LLM could return malicious data that is then parsed and written to the users.json file. This is a prompt injection surface because the LLM output is trusted without validation.
ImpactA compromised LLM could inject arbitrary fields or values into the user object, potentially leading to data corruption or injection of malicious content into the JSON file. However, the impact is limited because the data is only written to a local JSON file and not executed.
FixValidate the structure and types of the parsed JSON before writing to the database. Use a schema validation library like Zod to ensure only expected fields are present and of the correct type.
115server.tool(
116 'create-random-user',
117 'Create a random user with fake data',
118 {
119 title: 'Create Random User',
120 readOnlyHint: false,
121 destructiveHint: false,
122 idempotentHint: false,
123 openWorldHint: true,
124 },
125 async () => {
126 const res = await server.server.request(
127 {
128 method: 'sampling/createMessage',
129 params: {
130 messages: [
131 {
132 role: 'user',
133 content: {
134 type: 'text',
135 text: 'Generate fake user data...',
136 },
137 },
138 ],
139 maxTokens: 1024,
140 },
141 },
142 CreateMessageResultSchema
143 );
144 ...
145 }
146);// Local-only MCP, low impact as it only affects user experience.
The create-random-user tool uses the sampling/createMessage MCP method to generate fake user data. This method may require user consent or approval depending on the client implementation, but the tool does not explicitly request or handle user confirmation. The tool is marked with openWorldHint: true, but the sampling request could be unexpected to the user.
ImpactA user might not expect that invoking create-random-user will trigger an LLM sampling request, which could consume tokens or produce unexpected output. However, this is a minor usability issue rather than a security vulnerability.
FixConsider adding a confirmation step or documenting that the tool uses LLM sampling. Alternatively, generate fake data locally instead of relying on LLM.