fix(mcp): restrict env var expansion in MCP configs

Block sensitive env var interpolation in MCP config expansion so repo and plugin MCP definitions cannot exfiltrate secrets by default.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-02 14:55:01 +09:00
parent a637cca702
commit e8c5727a22
9 changed files with 260 additions and 0 deletions
@@ -57,6 +57,7 @@ beforeEach(() => {
spyOn(agentLoader, "loadProjectAgents" as any).mockReturnValue({})
spyOn(mcpLoader, "loadMcpConfigs" as any).mockResolvedValue({ servers: {} })
spyOn(mcpLoader, "setAdditionalAllowedMcpEnvVars").mockImplementation(() => {})
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockResolvedValue({
commands: {},
@@ -103,6 +104,7 @@ afterEach(() => {
;(agentLoader.loadUserAgents as any)?.mockRestore?.()
;(agentLoader.loadProjectAgents as any)?.mockRestore?.()
;(mcpLoader.loadMcpConfigs as any)?.mockRestore?.()
;(mcpLoader.setAdditionalAllowedMcpEnvVars as any)?.mockRestore?.()
;(pluginLoader.loadAllPluginComponents as any)?.mockRestore?.()
;(mcpModule.createBuiltinMcps as any)?.mockRestore?.()
;(shared.log as any)?.mockRestore?.()
@@ -173,6 +175,36 @@ describe("Sisyphus-Junior model inheritance", () => {
})
})
describe("MCP env allowlist initialization", () => {
test("sets the configured MCP env allowlist before plugin loading", async () => {
// given
const pluginConfig = createPluginConfig({
mcp_env_allowlist: ["CUSTOM_API_KEY", "CUSTOM_AUTH_TOKEN"],
})
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(mcpLoader.setAdditionalAllowedMcpEnvVars).toHaveBeenCalledWith([
"CUSTOM_API_KEY",
"CUSTOM_AUTH_TOKEN",
])
})
})
describe("Plan agent demote behavior", () => {
test("orders core agents as sisyphus -> hephaestus -> prometheus -> atlas", async () => {
// #given