Stu Mason
Stu Mason

Activity

Issue Resolved

Issue #159 closed: env_vars tool result leaks plaintext value and real_value

Issue

The env_vars / bulk_env_update tool (and the underlying GET /applications/{uuid}/envs endpoint) returns the full env var record in the MCP tool_result, including value and real_value in plaintext. When an AI agent calls the tool to manage environment variables, the value enters the agent's conversation transcript and session storage — defeating the operator's confidentiality expectation for secret-class env vars.

Reproduction

  1. Have a Coolify app with env var FOO=secret123
  2. Call the MCP tool that lists / creates / updates envs on that app
  3. Observe the tool_result JSON contains "value": "secret123" and "real_value": "secret123"
  4. The AI agent now has the plaintext value in context + transcript

Impact

Any agent using coolify-mcp with write permissions effectively also reads back every value it touches (plus every value already on the app, via list). For secret-bearing env vars (API keys, database URLs, tokens), this is a leak into:

  • The agent's context window (in-memory)
  • The agent's session transcript storage (on disk, per the agent's host)
  • Any logs the agent itself produces

Proposed fix

Three options, preference order:

  1. Default: mask values in MCP responses. Return "value": "***" (or omit entirely) for any env var created or read via the MCP. Preserve the metadata (key, uuid, flags, timestamps) so operations on the record still work.
  2. Opt-in reveal: add a --reveal / reveal=true parameter the caller must set explicitly. Default masked.
  3. Per-field sensitivity flag: if Coolify's env var record has or could have an is_secret flag, mask only those. Less safe (defaults allow leaks), but lower-impact on existing callers.

Option 1 matches what n8n's public API does for password-type credential fields and what 1Password's CLI does by default.

Context

We're building a secret-capture tool that routes user-typed secrets to destinations including Coolify. To avoid the value entering our agent's transcript, we bypassed the MCP and called Coolify's REST directly with curl ... -o /dev/null on writes. Would prefer to use the MCP if responses were masked.

Our adapter: https://github.com/D1DX/secret-capture-skill/blob/main/scripts/adapters/coolify.sh

Happy to submit a PR — just want to align on the approach first.