Skip to content

Security: strata tool add cursor modifies ~/.cursor/mcp.json without confirmation or backup #1432

@north-echo

Description

@north-echo

Summary

The strata tool add cursor command directly reads and writes the user's global Cursor MCP configuration file (~/.cursor/mcp.json) without user confirmation, backup, or atomic write protection. This is inconsistent with the VSCode and Claude/Gemini integrations in the same codebase, which delegate config management to the respective platform CLIs (code --add-mcp, claude mcp add).

Affected Code

File: open-strata/src/strata/utils/tool_integration.py

  • add_strata_to_cursor() (lines 109-155): Reads ~/.cursor/mcp.json, injects {"strata": {"command": "strata"}} into mcpServers, writes back.
  • ensure_json_config() (lines 45-69): On JSON parse failure, silently creates a new empty config, potentially discarding all existing MCP server entries.
  • save_json_config() (lines 72-81): Direct open("w") + json.dump() with no atomic write pattern.

Reproduction

  1. Install strata: pip install strata
  2. Configure Cursor with several MCP servers in ~/.cursor/mcp.json
  3. Run: strata tool add cursor
  4. Observe: ~/.cursor/mcp.json modified with no confirmation prompt
  5. To observe corruption risk: Manually corrupt ~/.cursor/mcp.json with invalid JSON, then run strata tool add cursor — existing config is silently replaced with {"mcpServers": {"strata": {"command": "strata"}}}

Inconsistency With Other Integrations

Platform Method Safety
VSCode code --add-mcp CLI Platform-managed config handling
Claude claude mcp add CLI Platform-managed config handling
Gemini gemini mcp add CLI Platform-managed config handling
Cursor Direct file write to ~/.cursor/mcp.json No platform API — strata reimplements config management

Issues

1. No user confirmation

The command writes to ~/.cursor/mcp.json immediately with no prompt. A --dry-run flag or interactive confirmation ("This will modify ~/.cursor/mcp.json. Continue? [y/N]") would be appropriate.

2. Silent corruption recovery

ensure_json_config() (line 67) catches json.JSONDecodeError and returns an empty dict. If the user's config is temporarily malformed (e.g., Cursor was mid-write, or the user was editing it), running strata tool add cursor will silently discard all existing MCP server configurations.

3. No atomic writes

save_json_config() uses open("w") which truncates the file before writing. If the process crashes or is interrupted during json.dump(), the file is left empty or partially written. Standard mitigation: write to a temp file, then os.rename().

4. No backup

The original config is not preserved before modification. A simple shutil.copy2() to mcp.json.bak before writing would provide recovery.

5. TOCTOU race condition

Between reading the config (line 138) and writing it back (line 149), another process (Cursor IDE, another strata instance, user editing) could modify the file. The strata write would silently overwrite those changes.

Mitigating Factors

  • The operation is user-initiated (requires running strata tool add cursor)
  • Existing MCP server entries are preserved via recursive merge (update_json_recursively)
  • The config path (~/.cursor/mcp.json) matches Cursor's expected location

Suggested Fixes

  1. Add confirmation prompt before writing to global config
  2. Add --dry-run flag to preview changes
  3. Implement atomic writes (temp file + os.rename())
  4. Create backup (mcp.json.bak) before modification
  5. Fix silent corruption: On JSONDecodeError, warn and abort rather than silently creating empty config
  6. Document that this command directly modifies ~/.cursor/mcp.json

Context

Found during a security review of the MCP server ecosystem. CWE-269 (Improper Privilege Management).

Reporter: Christopher Lusk — [email protected] — North Echo Security Research

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions