Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ describe("canUseTool MCP approval enforcement", () => {
expect(result.behavior).toBe("allow");
});

it("bypasses the PostHog exec gate in auto mode", async () => {
it("prompts through the PostHog exec gate in auto mode", async () => {
setMcpToolApprovalStates({ mcp__posthog__exec: "approved" });
const hasApproval = vi.fn().mockReturnValue(false);
const addApproval = vi.fn().mockResolvedValue(undefined);
Expand All @@ -215,12 +215,23 @@ describe("canUseTool MCP approval enforcement", () => {
addPostHogExecApproval: addApproval,
},
},
client: createClient({
outcome: { outcome: "selected", optionId: "allow" },
}),
});
const result = await canUseTool(context);

// Auto mode only auto-approves file edits and shell commands; destructive
// PostHog sub-tools must still reach the client as a permission prompt.
expect(result.behavior).toBe("allow");
expect(context.client.requestPermission).not.toHaveBeenCalled();
expect(hasApproval).not.toHaveBeenCalled();
expect(hasApproval).toHaveBeenCalledWith("experiment-update");
expect(context.client.requestPermission).toHaveBeenCalledWith(
expect.objectContaining({
toolCall: expect.objectContaining({
title: "The agent wants to run `experiment-update` on PostHog",
}),
}),
);
expect(addApproval).not.toHaveBeenCalled();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,10 +778,10 @@ export async function canUseTool(
if (isPostHogExecTool(toolName)) {
const subTool = extractPostHogSubTool(toolInput);
if (subTool && isPostHogDestructiveSubTool(subTool)) {
if (
session.permissionMode === "auto" ||
session.permissionMode === "bypassPermissions"
) {
// "auto" deliberately does NOT skip this gate: the mode only promises
// hands-off file edits and shell commands, and destructive PostHog
// sub-tools must still surface a permission prompt to the client.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Cloud Auto Mode Still Fails Open

When an auto-mode cloud session has no desktop connected, this branch reaches the approval flow, but the cloud permission client falls through to selecting the first option, allow. An unapproved destructive PostHog sub-tool therefore still executes without presenting a permission request, so the changed gate does not protect that reachable auto-mode path.

if (session.permissionMode === "bypassPermissions") {
return {
behavior: "allow",
updatedInput: toolInput as Record<string, unknown>,
Expand Down
Loading