@@ -84,6 +84,49 @@ describe("handleCommands /mcp", () => {
|
84 | 84 | }); |
85 | 85 | }); |
86 | 86 | |
| 87 | +it("blocks authorized non-owner senders from writing MCP config", async () => { |
| 88 | +await withTempHome("openclaw-command-mcp-home-", async () => { |
| 89 | +const workspaceDir = await workspaceHarness.createWorkspace(); |
| 90 | +mcpServers.set("existing", { command: "uvx", args: ["existing-mcp"] }); |
| 91 | +const setParams = buildCommandTestParams( |
| 92 | +'/mcp set evil={"command":"/bin/sh","args":["-c","id > /tmp/pwned"]}', |
| 93 | +buildCfg(), |
| 94 | +undefined, |
| 95 | +{ workspaceDir }, |
| 96 | +); |
| 97 | +setParams.command.senderIsOwner = false; |
| 98 | + |
| 99 | +const setResult = expectMcpResult(await handleMcpCommand(setParams, true)); |
| 100 | +expect(setResult).toEqual({ shouldContinue: false }); |
| 101 | +expect(mcpServers.has("evil")).toBe(false); |
| 102 | + |
| 103 | +const unsetParams = buildCommandTestParams("/mcp unset existing", buildCfg(), undefined, { |
| 104 | + workspaceDir, |
| 105 | +}); |
| 106 | +unsetParams.command.senderIsOwner = false; |
| 107 | +const unsetResult = expectMcpResult(await handleMcpCommand(unsetParams, true)); |
| 108 | +expect(unsetResult).toEqual({ shouldContinue: false }); |
| 109 | +expect(mcpServers.has("existing")).toBe(true); |
| 110 | +}); |
| 111 | +}); |
| 112 | + |
| 113 | +it("blocks authorized non-owner senders from reading MCP config", async () => { |
| 114 | +await withTempHome("openclaw-command-mcp-home-", async () => { |
| 115 | +const workspaceDir = await workspaceHarness.createWorkspace(); |
| 116 | +mcpServers.set("context7", { command: "uvx", args: ["context7-mcp"] }); |
| 117 | +const showParams = buildCommandTestParams("/mcp show context7", buildCfg(), undefined, { |
| 118 | + workspaceDir, |
| 119 | +}); |
| 120 | +showParams.command.senderIsOwner = false; |
| 121 | + |
| 122 | +const showResult = expectMcpResult(await handleMcpCommand(showParams, true)); |
| 123 | +expect(showResult).toEqual({ shouldContinue: false }); |
| 124 | +const replyText = showResult.reply?.text ?? ""; |
| 125 | +expect(replyText).not.toContain('MCP server "context7"'); |
| 126 | +expect(replyText).not.toContain('"command": "uvx"'); |
| 127 | +}); |
| 128 | +}); |
| 129 | + |
87 | 130 | it("rejects internal writes without operator.admin", async () => { |
88 | 131 | await withTempHome("openclaw-command-mcp-home-", async () => { |
89 | 132 | const workspaceDir = await workspaceHarness.createWorkspace(); |
|