Skip to content

fix: patch 5 security vulnerabilities across electron, server, and proxy layers#1292

Open
eren-karakus0 wants to merge 1 commit intoeigent-ai:mainfrom
eren-karakus0:fix/critical-security-vulnerabilities-and-race-conditions
Open

fix: patch 5 security vulnerabilities across electron, server, and proxy layers#1292
eren-karakus0 wants to merge 1 commit intoeigent-ai:mainfrom
eren-karakus0:fix/critical-security-vulnerabilities-and-race-conditions

Conversation

@eren-karakus0
Copy link

Related Issue

Closes #1291

Description

This PR patches 5 security and correctness vulnerabilities discovered during a cross-layer code audit of the Electron main process, server model layer, and proxy controller.

1. CRITICAL — localfile:// Path Traversal (electron/main/index.ts)

Before: The localfile:// protocol handler used path.normalize() which does NOT prevent directory traversal. A request to localfile:///../../../etc/passwd would resolve to /etc/passwd and serve the file contents.

After: Added path.resolve() + directory boundary validation against an allowlist (os.homedir(), app.getPath('userData'), app.getPath('temp')). Requests outside these directories now return 403 Forbidden. The check also prevents prefix-matching attacks (/home/user-evil/ won't match /home/user/).

2. CRITICAL — Hardcoded Share Token Secret (server/app/model/chat/chat_share.py)

Before: SECRET_KEY defaulted to the hardcoded string "EGB1WRC9xMUVgNoIPH8tLw" and SALT to "r4U2M". Since the source code is public, anyone could forge valid share tokens.

After: When CHAT_SHARE_SECRET_KEY or CHAT_SHARE_SALT environment variables are not set, the system generates a cryptographically secure random key using secrets.token_urlsafe() and logs a warning. Token roundtrip still works correctly; tokens simply won't survive server restarts unless the env var is configured.

3. HIGH — Double requestSingleInstanceLock() (electron/main/index.ts)

Before: The lock was acquired twice — once at module level (line 212) without event handlers, and again inside setupSingleInstanceLock(). The second call could release and re-acquire the lock, creating a race window for duplicate instances. Protocol URLs between the calls were also lost.

After: Removed the redundant second requestSingleInstanceLock() call. The module-level call (line 212) still guards against duplicate instances. setupSingleInstanceLock() now only registers second-instance and open-url event handlers.

4. HIGH — Hardcoded Debug URL in execute-command (electron/main/index.ts)

Before: Every command executed via the execute-command IPC handler had --debug --host dev.eigent.ai/api/oauth/notion/callback?code=1 appended to it. The correct production code (const commandWithHost = command;) was commented out.

After: Removed the hardcoded debug flags. Commands now execute as-is.

5. HIGH — Unencoded Query in Google Search URL (server/app/controller/mcp/proxy_controller.py)

Before: The query parameter was interpolated directly into the Google Custom Search API URL via f-string: f"...&q={query}&...". Queries containing &, =, #, or Unicode characters would break the URL or allow parameter injection.

After: Added urllib.parse.quote_plus() to properly encode the query parameter: f"...&q={quote_plus(query)}&...".

Testing Evidence (REQUIRED)

  • I have included human-verified testing evidence in this PR.
  • This PR includes frontend/UI changes, and I attached screenshot(s) or screen recording(s).
  • No frontend/UI changes in this PR.

Tests added:

  1. test/unit/electron/main/index.test.ts — 8 new tests for localfile:// path traversal prevention:

    • Validates allowed paths (home, userData, temp directories)
    • Blocks traversal attacks (/../../../etc/passwd)
    • Blocks absolute paths outside allowed directories
    • Blocks encoded traversal after normalize
    • Prevents prefix-matching attacks (/home/user-evil/)
  2. server/tests/test_chat_share.py — 7 new tests for secret key generation:

    • _get_secret_key() returns env var when set
    • _get_secret_key() generates random key when env not set
    • Generated keys are never the old hardcoded value
    • Each call produces unique keys (cryptographic randomness)
    • Salt generation follows same secure pattern
    • Token roundtrip works with randomly generated keys
  3. server/tests/test_proxy_controller.py — 6 new tests for URL encoding:

    • Simple queries pass through correctly
    • Special characters (&, =) are encoded
    • Hash character (#) doesn't truncate URL
    • Unicode characters are encoded
    • Plus signs (C++) are handled correctly
    • Parameter injection (test&key=STOLEN_KEY) is prevented

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Contribution Guidelines Acknowledgement

…oxy layers

- localfile:// path traversal: add directory boundary validation to prevent
  arbitrary file reads via ../../../etc/passwd style traversal attacks
- Hardcoded share token secret: replace public default key (EGB1WRC9xMUVgNoIPH8tLw)
  with random ephemeral generation when CHAT_SHARE_SECRET_KEY is not set
- Double requestSingleInstanceLock: remove redundant second call that could
  release and re-acquire the lock, creating a race window for duplicate instances
- execute-command debug leak: remove hardcoded --debug --host dev.eigent.ai
  flag that was left over from development and breaks production MCP installations
- Google Search URL injection: URL-encode query parameter to prevent parameter
  injection and broken URLs when queries contain &, =, #, or unicode characters
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.

Security: Path traversal, hardcoded secrets, duplicate lock, debug leak, and URL injection

1 participant