Skip to content

fix: prevent credential_process hang on Windows in stdio transport mode#293

Open
rshevchuk-git wants to merge 1 commit into
mainfrom
fix/credential-process-stdin-inheritance
Open

fix: prevent credential_process hang on Windows in stdio transport mode#293
rshevchuk-git wants to merge 1 commit into
mainfrom
fix/credential-process-stdin-inheritance

Conversation

@rshevchuk-git
Copy link
Copy Markdown
Collaborator

Summary

  • Monkey-patches botocore's ProcessProvider._retrieve_credentials_using to pass stdin=subprocess.DEVNULL when spawning credential_process subprocesses
  • Prevents the child process from inheriting the MCP JSON-RPC pipe as its stdin, which causes Popen.communicate() to hang indefinitely on Windows (IOCP)
  • Adds comprehensive stress tests validating the fix across concurrent calls, pipe inheritance, and end-to-end credential resolution

Problem

When mcp-proxy-for-aws runs in stdio transport mode, its stdin is the MCP JSON-RPC pipe. Botocore's ProcessProvider spawns credential_process subprocesses without specifying stdin, so the child inherits the pipe. On Windows this causes the subprocess to hang indefinitely because it holds an open handle to the pipe, blocking Popen.communicate() from completing.

This affects any user with credential_process in their AWS profile (e.g., isengardcli credentials) when using the MCP proxy on Windows through IDE integrations (Kiro, Cline, Claude Code).

Fixes D454977820

Test plan

  • 12 new unit tests covering:
    • Patch is active (stdin=DEVNULL present in source)
    • Pipe inheritance behavior with/without fix
    • Error handling preserved (failed process, invalid version)
    • Concurrent credential_process calls with active MCP pipe (10 threads)
    • End-to-end boto3 session with credential_process + simulated MCP pipe
  • All 192 existing unit tests pass
  • Verified RefreshableCredentials (expiring creds) path works
  • Verified static credentials profiles are unaffected
  • Verified failed credential_process error propagation works

Monkey-patch botocore's ProcessProvider to pass stdin=subprocess.DEVNULL
when spawning credential_process subprocesses. Without this, the child
inherits the MCP JSON-RPC pipe as stdin, causing Popen.communicate() to
hang indefinitely on Windows (IOCP) due to the open pipe handle.

Fixes D454977820
@rshevchuk-git rshevchuk-git requested a review from a team as a code owner May 27, 2026 10:16
@rshevchuk-git rshevchuk-git requested review from arangatang and jinet May 27, 2026 10:16
import httpx
import json
import logging
import subprocess
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive. We dont pass user-controlled input to subprocess, and we use compat_shell_split() (no shell=True). Literally replicating what botocore itself already does, just adding stdin=subprocess.DEVNULL

https://github.com/boto/botocore/blob/a6352f4e23fd71461ca9d74d48307dda8d859d31/botocore/credentials.py#L1101


def _retrieve_credentials_using(self, credential_process):
process_list = compat_shell_split(credential_process)
p = self._popen(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the patch be simpler if we just override self._popen with a patched popen that has stdin=subprocess.DEVNULL by default?

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.

4 participants