SSWConsulting / SSWConsulting/SSW.MeetupMCP

Installers persist configuration to shell history and process command lines

Open
#10 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Type: Bug Type: DevOps
Dominant language
TypeScript
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Summary

Both installers take every configuration value as a command-line parameter, which writes them to several places outside the operator's control. The Claude installer tries to avoid this and the mitigation does not hold.

To be clear about scope: the RSA private key never goes near either script. What leaks is the client ID, member ID, signing key ID and the key's filesystem path. Not credential material, but enough to tell someone exactly which OAuth client and account to target, and where the key lives on disk.

Where the values end up

  1. PSReadLine console history, at %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt. Plaintext, no expiry, and it roams with OneDrive Known Folder Move or a roaming profile. PSReadLine does scrub sensitive lines, but its default filter is the regex password|asplaintext|token|apikey|secret, and none of -ClientId, -MemberId, -SigningKeyId or -PrivateKeyPath match it. The invocation documented in docs/setup.md is written to that file verbatim.
  2. Child process command lines, readable by any same-user process via Get-CimInstance Win32_Process, and captured by Windows Security Event 4688 where command-line auditing is enabled, by Sysmon Event 1, and by most EDR agents. On a managed build those records ship to a SIEM and outlive the machine.
  3. PowerShell transcription, if enabled by Group Policy.
  4. The MCP client config at rest, in ~/.codex/config.toml or ~/.claude.json. This one is inherent to how stdio MCP servers receive environment variables and is not avoidable.

The Claude installer's mitigation does not work

scripts/install-claude.ps1 deliberately keeps the values off the PowerShell command line by stashing the config in $env:CLAUDE_MCP_SERVER_JSON and shelling out to a Node helper. But scripts/register-claude-mcp.mjs:11 then passes that same JSON straight back as an argv element to spawnSync.

Verified by running the real helper against a stub claude binary:

argv[6] = {"type":"stdio",...,"env":{"MEETUP_CLIENT_ID":"REAL_CLIENT_ID","MEETUP_MEMBER_ID":"REAL_MEMBER_ID","MEETUP_SIGNING_KEY_ID":"REAL_KEY_ID","MEETUP_PRIVATE_KEY_PATH":"C:\secure\meetup\key.pem",...}}

Same data, same exposure class, one process further down. scripts/install-codex.ps1:24 has the same problem more directly, via seven --env "NAME=value" arguments.

Suggested fix

Have the installer read configuration from a .env file rather than from parameters. .env.example is already in the right shape and .env is already gitignored, so this removes items 1 through 3 entirely with no new concepts for the operator.

Once configuration comes from a file, the installer has no reason to be PowerShell. A single node scripts/install.mjs would work on macOS, Linux and Windows, and both .ps1 files plus the Node helper could be deleted.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with scripts/install-claude.ps1, scripts/install-codex.ps1, and scripts/register-claude-mcp.mjs, then compare their configuration handling with .env.example and the documented setup in docs/setup.md. Confirm the replacement reads configuration from .env, avoids putting values in PowerShell or child-process arguments, and provides a cross-platform node scripts/install.mjs entry point.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, powershell, typescript
Domain
security, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.