security(feishu): bind doc create grants to trusted requester context (#31184)

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Tak Hoffman
2026-03-01 20:51:45 -06:00
committed by GitHub
parent e482da6682
commit bbab94c1fe
9 changed files with 142 additions and 91 deletions

View File

@@ -0,0 +1,28 @@
import { describe, expect, it, vi } from "vitest";
const resolvePluginToolsMock = vi.fn(() => []);
vi.mock("../plugins/tools.js", () => ({
resolvePluginTools: (params: unknown) => resolvePluginToolsMock(params),
}));
import { createOpenClawTools } from "./openclaw-tools.js";
describe("createOpenClawTools plugin context", () => {
it("forwards trusted requester sender identity to plugin tool context", () => {
createOpenClawTools({
config: {} as never,
requesterSenderId: "trusted-sender",
senderIsOwner: true,
});
expect(resolvePluginToolsMock).toHaveBeenCalledWith(
expect.objectContaining({
context: expect.objectContaining({
requesterSenderId: "trusted-sender",
senderIsOwner: true,
}),
}),
);
});
});

View File

@@ -187,6 +187,8 @@ export function createOpenClawTools(options?: {
sessionKey: options?.agentSessionKey,
messageChannel: options?.agentChannel,
agentAccountId: options?.agentAccountId,
requesterSenderId: options?.requesterSenderId ?? undefined,
senderIsOwner: options?.senderIsOwner ?? undefined,
sandboxed: options?.sandboxed,
},
existingToolNames: new Set(tools.map((tool) => tool.name)),

View File

@@ -63,6 +63,10 @@ export type OpenClawPluginToolContext = {
sessionKey?: string;
messageChannel?: string;
agentAccountId?: string;
/** Trusted sender id from inbound context (runtime-provided, not tool args). */
requesterSenderId?: string;
/** Whether the trusted sender is an owner. */
senderIsOwner?: boolean;
sandboxed?: boolean;
};

View File

@@ -1266,7 +1266,7 @@ describe("security audit", () => {
);
});
it("warns when Feishu doc tool is enabled because create supports owner_open_id", async () => {
it("warns when Feishu doc tool is enabled because create can grant requester access", async () => {
const cfg: OpenClawConfig = {
channels: {
feishu: {
@@ -1280,7 +1280,7 @@ describe("security audit", () => {
expectFinding(res, "channels.feishu.doc_owner_open_id", "warn");
});
it("does not warn for Feishu owner_open_id when doc tools are disabled", async () => {
it("does not warn for Feishu doc grant risk when doc tools are disabled", async () => {
const cfg: OpenClawConfig = {
channels: {
feishu: {

View File

@@ -519,11 +519,11 @@ function collectGatewayConfigFindings(
findings.push({
checkId: "channels.feishu.doc_owner_open_id",
severity: "warn",
title: "Feishu doc create can grant owner permissions",
title: "Feishu doc create can grant requester permissions",
detail:
'channels.feishu tools include "doc"; feishu_doc action "create" accepts owner_open_id and can grant document access to that user.',
'channels.feishu tools include "doc"; feishu_doc action "create" can grant document access to the trusted requesting Feishu user.',
remediation:
"Disable channels.feishu.tools.doc when not needed, and restrict tool access so untrusted prompts cannot set owner_open_id.",
"Disable channels.feishu.tools.doc when not needed, and restrict tool access for untrusted prompts.",
});
}