Skip to content

fix: address critical security vulnerabilities (path traversal, command injection, and more)#60

Open
19prince wants to merge 1 commit into
gemini-cli-extensions:mainfrom
19prince:security/fix-critical-vulnerabilities
Open

fix: address critical security vulnerabilities (path traversal, command injection, and more)#60
19prince wants to merge 1 commit into
gemini-cli-extensions:mainfrom
19prince:security/fix-critical-vulnerabilities

Conversation

@19prince
Copy link
Copy Markdown

Summary

Security audit of the MCP server identified several vulnerabilities. This PR fixes all of them.

Critical / High

  • Path traversal → arbitrary file read (fileHandler.ts): findInputFile() previously accepted absolute paths (e.g. /etc/passwd, ~/.ssh/id_rsa) and returned them verbatim for fs.readFile(), which then sent the contents to the Gemini API. Fix: reject absolute paths outright, reject .. sequences, resolve the final path and assert it stays inside the intended search root.

  • Command injection (imageGenerator.ts): openImagePreview() built shell commands via string interpolation — open "${filePath}" — and passed them to exec(). A path containing " or backticks could break out of the quoting. Fix: replaced with execFile() + argument array, removing shell involvement entirely.

Medium

  • No runtime input validation (index.ts): all tool arguments were accepted via bare TypeScript casts with no runtime enforcement. Added validateToolArgs() enforcing: non-empty prompt, 10 000 character limit, outputCount integer 1–8, steps integer 2–8, non-empty file with 255 char limit.

Low

  • Error messages leaking filesystem layout (imageGenerator.ts): "file not found" responses previously included the full list of searched paths (disclosing process.cwd(), $HOME, etc.). Replaced with a generic message.

  • Unvalidated NANOBANANA_MODEL env var (imageGenerator.ts): model name now checked against an allowlist of the three documented models; unknown values fall back to the default with a warning.

  • Unbounded file write (fileHandler.ts): saveImageFromBase64() now rejects API responses larger than 50 MB before writing to disk.

  • Vulnerable dependencies: npm audit fix resolves 5 CVEs — ReDoS in @modelcontextprotocol/sdk, ajv, qs; DoS in body-parser; HMAC bypass in jws.

Test plan

  • npm run build passes cleanly in mcp-server/
  • npm audit reports 0 vulnerabilities
  • edit_image with an absolute path (e.g. /etc/passwd) returns "File not found" rather than reading the file
  • edit_image with a ../ traversal path returns "File not found"
  • generate_image with an empty prompt returns a validation error
  • generate_image with outputCount: 99 returns a validation error
  • Image preview opens correctly on macOS/Linux (execFile path)

🤖 Generated with Claude Code

- Path traversal (High): findInputFile() now rejects absolute paths and
  path traversal sequences (../), resolves paths and verifies they stay
  within the intended search root before any fs.readFile call

- Command injection (High): openImagePreview() replaced exec() string
  interpolation with execFile() + argument array, removing shell
  involvement entirely

- Input validation (Medium): added validateToolArgs() in index.ts
  enforcing non-empty prompt, 10k char limit, integer ranges for
  outputCount/steps (1-8/2-8), non-empty file param

- Error message leakage (Low): replaced full filesystem search path
  disclosure with a generic not-found message

- Model name allowlist (Low): NANOBANANA_MODEL validated against known
  model identifiers; falls back to default with warning if unknown

- File size guard (Low): saveImageFromBase64() rejects API responses
  larger than 50 MB before writing to disk

- Vulnerable dependencies: npm audit fix resolves 5 CVEs including
  ReDoS in @modelcontextprotocol/sdk, ajv, qs; DoS in body-parser;
  HMAC bypass in jws

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Mar 18, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

tellang added a commit to tellang/nanobanana that referenced this pull request Apr 20, 2026
- fileHandler: use os.homedir() instead of `process.env.HOME || '~'`
  for Downloads/Desktop search paths. Node does not set HOME on
  Windows, so the previous expression produced literal `~\Downloads`
  that silently never matched.

- fileHandler: generateFilename now accepts a mimeType argument and
  derives the extension from it (JPEG -> jpg, PNG -> png, WebP -> webp,
  GIF -> gif), falling back to the caller's `format` only when the
  MIME type is missing or unrecognised. Previously the extension was
  always derived from `fileFormat` (default png), so JPEG bytes
  returned by the model were saved under a `.png` filename whenever
  `image/jpeg` came back in inlineData.

- imageGenerator: forward `seed` to generateContent via `config`.
  The MCP generate_image tool has always exposed a seed parameter
  and ImageGenerationRequest carried it, but the value was dropped
  before reaching the Google GenAI SDK, making seeded variations a
  no-op.

- imageGenerator: isValidBase64ImageData now checks PNG/JPEG/WebP/
  GIF magic bytes after the base64 shape check, so long base64-like
  strings that aren't actually images (logs, JSON payloads) are no
  longer accepted.

- commands/generate.toml: expose --no-preview flag. The MCP handler
  in index.ts already reads noPreview / no-preview, but the TOML
  parser prompt listed only --preview, so users had no documented
  way to force preview off.

- commands/icon.toml: strengthen the --sizes instruction to require
  parsing as an integer array (e.g. "16,32,64" -> [16, 32, 64]),
  since the TOML LLM parser was occasionally forwarding it as a
  plain string or a single integer.

The saveImageFromBase64 write race is deliberately left for PR gemini-cli-extensions#60,
which already modifies that function.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant