Skip to content

Windows: keyring probe passes but real cookie-session save silently falls back to a plaintext fileΒ #80

Description

@chirstius

Summary

On Windows, _keyring_available() reports the keyring as usable, the server logs πŸ” Using system keyring for token storage, and then the actual session save silently falls back to a plaintext file β€” because a real cookie-mode session is too large for Windows Credential Manager. Users who believe their credentials live in the encrypted OS vault instead have their live Monarch session cookies sitting in a plaintext file, with no clear signal that this happened.

Root cause

_keyring_available() (in src/monarch_mcp_server/secure_session.py) probes the backend by round-tripping a 1-byte sentinel ("1"):

keyring.set_password(KEYRING_SERVICE, _PROBE_USERNAME, "1")

That always succeeds on Windows. But Windows Credential Manager (keyring.backends.Windows.WinVaultKeyring) has a hard cap on the credential blob size. A cookie-mode session blob β€” {"auth_mode": "cookie", "device_uuid": ..., "cookies": {session_id, csrftoken, cf_clearance, __cf_bm, ...}} β€” is ~950 chars, which exceeds the cap. So save_session_blob() throws inside the try, hits the except, and quietly writes the plaintext file instead:

except Exception as e:
    logger.warning(f"⚠️  Keyring save failed, falling back to file: {e}")
self._save_token_file(blob)   # plaintext

The only trace is a single WARNING line that's easy to miss; check_auth_status then also reports "no token found in keyring" even though auth works via the file, which compounds the confusion.

Reproduction / evidence

On Windows 11 (Credential Manager backend), CredWrite starts failing well below the documented limit:

  600 chars: OK
  700 chars: FAIL -> (8, 'CredWrite', 'Not enough memory resources are available to process this command.')
 1500 chars: FAIL -> (1783, 'CredWrite', 'The stub received bad data.')

The documented Windows limit is 2560 UTF-16 chars; some machines are stricter. Either way, a cookie session blob exceeds it. This is the same platform limitation OpenAI Codex hit for OAuth tokens on Windows: openai/codex#10353 (closed, no platform-level fix β€” the token simply cannot go in the vault).

Impact

  • Silent security downgrade on Windows: live session cookies stored as plaintext at rest, while the logs claim the keyring is in use.
  • Affects the recommended auth path (browser session cookies), i.e. most Windows users.

Suggested fixes

  1. Make the availability probe size-aware so the "using keyring" decision reflects what will actually be stored (probe with a representative-size value, or catch the size failure at decision time). At minimum, make the fallback log unmistakable.
  2. Encrypt the file fallback at rest. On Windows, DPAPI (win32crypt.CryptProtectData, already available via the pywin32 dependency) gives the same per-user protection Credential Manager uses, with no size cap. No-op on other platforms.

I'll open a PR implementing (2), with transparent migration of existing plaintext files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions