T09 · Insecure Skill Coding Practices
- Location
core.mjs:242- Finding
Unrestricted Local File Read Exposed Through the MCP Image-Editing Tool
- Content
View full analysis
Vulnerability Details
File Location:
core.mjs:242-273; reachable throughmcp-server.mjs:68-76andmcp-server.mjs:136-138
Vulnerability Type: Unrestricted filesystem access and resource-exhaustion risk
Risk Level: MediumVulnerable Code
core.mjs:242-273:javascript if (!prompt) throw new Error('prompt is required'); if (!image) throw new Error('image is required (URL or base64 data URI)'); const images = Array.isArray(image) ? image : [image]; if (images.length > 3) throw new Error('Maximum 3 source images'); // Build input with image(s) + text prompt const content = []; for (const img of images) { // If it looks like a file path, read and base64 encode let imageUrl = img; if (!img.startsWith('http') && !img.startsWith('data:')) { const data = readFileSync(img); const ext = img.split('.').pop().toLowerCase(); const mime = ext === 'png' ? 'image/png' : ext === 'webp' ? 'image/webp' : 'image/jpeg'; imageUrl = `data:${mime};base64,${data.toString('base64')}`; } content.push({ type: 'image_url', image_url: { url: imageUrl } }); } content.push({ type: 'text', text: prompt }); const response = await fetch(`${API_BASE}/images/edits`, { method: 'POST', headers: headers(), body: JSON.stringify({ model, image: images[0], prompt, n, response_format, }), });mcp-server.mjs:68-76:javascript { name: 'grok_edit_image', description: 'Edit images using natural language with Grok Imagine. Provide source image URL and edit instruction.', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Edit instruction' }, image: { type: 'string', description: 'Source image URL or base64 data URI' }, }, required: ['prompt', 'image'], }, },mcp-server.mjs:136-138:javascript case 'grok_edit_image': result = ...[truncated 3204 chars]- Remediation
View remediation
Remediation Suggestions
-
Enforce the documented MCP contract by accepting only explicitly validated HTTPS URLs and approved image data URIs:
- Parse URLs with the platform URL parser.
- Require the
https:protocol. - Validate data-URI media types against an image allowlist.
- Reject all other strings instead of treating them as paths.
-
If local-file editing is intentionally supported, expose it as an explicit, separately documented capability:
- Require user confirmation before reading a local file.
- Resolve the supplied path with
realpath. - Restrict resolved paths to a dedicated user-approved media directory.
- Reject path traversal, symbolic-link escapes, devices, sockets, FIFOs, and other non-regular files.
- Verify file signatures rather than trusting filename extensions.
- Enforce strict byte-size limits before reading.
- Use asynchronous file operations to avoid blocking the MCP event loop.
-
Correct the outbound request construction. Send the validated or encoded image value rather than the original path:
javascript body: JSON.stringify({ model, image: validatedImageUrl, prompt, n, response_format, });-
Remove the unused
contentconstruction if the xAI endpoint does not require it. Avoid reading any file unless its bytes will be used for the requested and authorized operation. -
Add tests covering arbitrary absolute paths, traversal paths, symbolic links, oversized files, special files, malformed data URIs, unsupported URL schemes, and MCP schema bypass attempts.
-
