[ ⌘K ]
← BACK TO SEARCH

arikusi/nakkas

critical

MCP server that turns AI into an SVG artist

This MCP server enables AI to generate animated SVG graphics from JSON configurations. It provides tools to render SVG, preview as PNG, and save to di...

purpose: This MCP server enables AI to generate animated SVthreat: local only
TypeScript8May 20, 2026May 20, 2026GITHUB
aianimationcss-animationgenerative-artmcpmcp-servermodelcontextprotocolsvgtypescriptvector
5/20/2026
medium4 findings
src/index.ts
266async ({ content, outputPath, format, width }) => {
267    const start = Date.now();
268    try {
269      const savedPath = await saveContent(content, outputPath, format, width);
270      const elapsed = Date.now() - start;
271      console.error(`[nakkas] save OK — ${savedPath}, ${elapsed}ms`);
272      return {
273        content: [{ type: "text", text: `Saved to: ${savedPath}` }],
274      };
275    } catch (err) {
276      const message = err instanceof Error ? err.message : String(err);
277      console.error(`[nakkas] save ERROR — ${message}`);
278      return {
279        content: [{ type: "text", text: `Error saving file: ${message}` }],
280        isError: true,
281      };
282    }
283  }
medium1 finding
src/index.ts
266async ({ content, outputPath, format, width }) => {
267    const start = Date.now();
268    try {
269      const savedPath = await saveContent(content, outputPath, format, width);
270      const elapsed = Date.now() - start;
271      console.error(`[nakkas] save OK — ${savedPath}, ${elapsed}ms`);
272      return {
273        content: [{ type: "text", text: `Saved to: ${savedPath}` }],
274      };
275    } catch (err) {
src/index.ts:23 -> src/save.js

// Local-only MCP, requires compromised LLM to exploit. However, if the MCP is exposed to untrusted prompts (e.g., via a network-facing interface), this becomes a high-severity file write vulnerability.

The save tool accepts an outputPath parameter from the user without validating that it stays within an intended directory. The description says 'The directory must already exist' but does not restrict the path. An attacker could use path traversal sequences (e.g., '../') to write files outside the intended workspace, potentially overwriting system files or writing to sensitive locations.

ImpactAn attacker could write arbitrary SVG or PNG files to any location the server process has write access to, potentially overwriting configuration files, scripts, or other critical data.

FixValidate that outputPath resolves to a path within a designated output directory. Use path.resolve and check that the resolved path starts with the allowed base directory. Reject paths containing '..' or absolute paths if not intended.

medium1 finding
src/index.ts
189async ({ content, format, width }) => {
190    const start = Date.now();
191    try {
192      const pngBuffer = renderPreview(content, format, width);
193      const base64 = pngBuffer.toString("base64");
194      const elapsed = Date.now() - start;
195      console.error(`[nakkas] preview OK — ${pngBuffer.length} bytes, ${elapsed}ms`);
196      return {
197        content: [{ type: "image", data: base64, mimeType: "image/png" }],
198      };
src/index.ts:21 -> src/preview.jssrc/index.ts:23 -> src/save.js

// Local-only MCP, requires compromised LLM to exploit. Denial of service could affect the local system.

The preview and save tools accept a 'content' string without any size limits. An attacker could provide an extremely large SVG string, causing excessive memory usage or disk writes, leading to denial of service.

ImpactAn attacker could cause the server to consume excessive memory or disk space, potentially crashing the process or filling up storage.

FixAdd a maximum length check on the content string (e.g., reject if > 10 MB). Also consider limiting the output file size in the save tool.

low1 finding
src/index.ts
189async ({ content, format, width }) => {
190    const start = Date.now();
191    try {
192      const pngBuffer = renderPreview(content, format, width);
193      const base64 = pngBuffer.toString("base64");
194      const elapsed = Date.now() - start;
195      console.error(`[nakkas] preview OK — ${pngBuffer.length} bytes, ${elapsed}ms`);
196      return {
197        content: [{ type: "image", data: base64, mimeType: "image/png" }],
198      };
199    } catch (err) {
200      const message = err instanceof Error ? err.message : String(err);
201      console.error(`[nakkas] preview ERROR — ${message}`);
202      return {
203        content: [{ type: "text", text: `Error rendering preview: ${message}` }],
204        isError: true,
205      };
206    }
207  }
src/index.ts:21 -> import { renderPreview } from "./preview.js";

// Local-only MCP, requires compromised LLM to exploit. Severity reduced from medium to low.

The preview tool accepts an SVG string and renders it to PNG. If the SVG contains external references (e.g., <image href="http://..."> or <use href="...">), the rendering engine may fetch those resources, leading to server-side request forgery (SSRF) or resource exhaustion. Additionally, a malicious SVG could cause denial of service via billion laughs attack or other XML bombs.

ImpactA compromised LLM could cause the server to make outbound requests to internal or external hosts, potentially exfiltrating data or scanning networks. Also could cause high CPU/memory usage.

FixSanitize SVG content before rendering: strip external references, disable external entity resolution, and set resource limits (e.g., max size, timeout). Use a secure SVG parser that disables network access.

shell.execenv.exposurebrowser.automationfilesystem.write
85
LLM-based
low findings+10
medium findings+75
scoringcompleted