You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Restore the user-facing ability to add/edit MCP servers post-deploy, lost in #590 (AISEC-C2 RCE closure), via a structured endpoint that validates inputs at the schema level — not raw JSON.
Context
#590 (Apr 30 2026) closed the .mcp.json RCE-by-config bypass by removing .mcp.json and .mcp.json.template from the user-facing ALLOWED_CREDENTIAL_PATHS and adding them to the agent-server's EDIT_PROTECTED_PATHS. The capability was insecure-by-design: any owner with raw write access to .mcp.json could inject {"mcpServers": {"e": {"command": "/bin/sh", "args": ["-c", "cat /proc/1/environ"]}}} and gain RCE on agent restart.
Summary
Restore the user-facing ability to add/edit MCP servers post-deploy, lost in #590 (AISEC-C2 RCE closure), via a structured endpoint that validates inputs at the schema level — not raw JSON.
Context
#590 (Apr 30 2026) closed the
.mcp.jsonRCE-by-config bypass by removing.mcp.jsonand.mcp.json.templatefrom the user-facingALLOWED_CREDENTIAL_PATHSand adding them to the agent-server'sEDIT_PROTECTED_PATHS. The capability was insecure-by-design: any owner with raw write access to.mcp.jsoncould inject{"mcpServers": {"e": {"command": "/bin/sh", "args": ["-c", "cat /proc/1/environ"]}}}and gain RCE on agent restart.UI feature regression after #590:
CredentialsPanel.vuefor.mcp.jsonreturns 400 (disallowed path).mcp.json.templatetemplate.yaml.env(the dominant credential workflow) is unchangedProposed design
New endpoint:
POST /api/agents/{name}/mcp-servers(andPUT/DELETEfor individual entries by id).Request body shape:
{ "id": "google-workspace", "transport": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-google-workspace"], "env": { "GOOGLE_TOKEN": "${GOOGLE_TOKEN}" } }Server-side validation:
transport∈{stdio, http, sse}enumstdio:commandMUST be in a managed allowlist (npx,uvx,docker,python,python3,node,bun,deno). No absolute paths, nobash -c, nosh -c.argsrejected if any element contains shell metacharacters that could escape the runner (;,|,$(, backticks, redirects)http/sse: HTTPS-only; hostname allowlist (npm registry, github raw, GCP/AWS endpoints, etc.) — same SSRF rules as SEC: Server-Side Request Forgery leads to Denial of Service #179 (skills library validation)envvalues are template references resolved from.env(${VAR}→ looked up in agent's.envfile). Arbitrary string values rejected.Owner-only authorization via
get_owned_agent_by_name(consistent withinject_credentials).Audit-logged via
platform_audit_service(event_action="mcp_server_set").UI replacement
Replace the raw JSON editor in
CredentialsPanel.vue(.mcp.jsonrow) with:Acceptance Criteria
POST/PUT/DELETE /api/agents/{name}/mcp-serversendpoints with the structured schema abovecommand, shell metacharacters inargs, non-HTTPS URLs, hostname outside allowlist, env values that aren't${VAR}references.mcp.jsonvia the platform-internal/api/credentials/updateflow (the only endpoint allowed to touch.mcp.json).mcp.jsonraw editor inCredentialsPanel.vueOut of scope
CLAUDE_CODE_OAUTH_TOKENout of/proc/1/environ) — separate threat-model issuecap_dac_override,cap_sys_ptrace) — flagged in SEC: PUT /api/agents/{name}/files guardrail bypass → .mcp.json write → RCE and Anthropic token exfiltration (AISEC-C2) #590 tech notesReferences