From bc68e5c06238e22b5aaaad28d9682a69002d1e1e Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 8 Nov 2026 20:55:50 -0600 Subject: [PATCH] fix(authz): link connection settings and stop the page search Two journeys showed agents searching for a web page after a board denial that named none: the general fallback told them to link the most specific page they knew. It now says to link a page only when its route is already known and not to search for one. Prompt injection prevention, decision model and fast response routes now link the connection settings page that holds those controls. Co-Authored-By: Claude Opus 5.5 --- server/src/__tests__/board-access-denial.test.ts | 2 ++ server/src/routes/authz.ts | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/__tests__/board-access-denial.test.ts b/server/src/__tests__/board-access-denial.test.ts index 991a9f30561..8b8759af6ac 100644 --- a/server/src/__tests__/board-access-denial.test.ts +++ b/server/src/__tests__/board-access-denial.test.ts @@ -35,6 +35,7 @@ describe("board-only denial", () => { ["post", `/api/companies/${COMPANY_ID}/secrets`, "[Open company secrets](//company/settings/secrets)"], ["post", `/api/secrets/${AGENT_ID}/rotate`, "[Open company secrets](//company/settings/secrets)"], ["post", `/api/companies/${COMPANY_ID}/budget-incidents/i-1/resolve?x=1`, "[Open budgets](//activity/budgets)"], + ["put", `/api/companies/${COMPANY_ID}/prompt-injection-prevention`, "[Open connection settings](//company/settings/connections)"], ["patch", `/api/agents/${AGENT_ID}/permissions`, `[Open the agent's permissions](//agents/${AGENT_ID}/permissions)`], ["post", `/api/agents/${AGENT_ID}/keys`, `[Open the agent's API keys](//agents/${AGENT_ID}/api-keys)`], ["post", `/api/agents/${AGENT_ID}/pause`, `[Open the agent's profile](//agents/${AGENT_ID})`], @@ -52,6 +53,7 @@ describe("board-only denial", () => { expect(res.body.code).toBe(BOARD_ACCESS_REQUIRED_CODE); expect(res.body.remediation).toContain("this denial is final"); expect(res.body.remediation).toContain("Paperclip web app or with their own board credentials"); + expect(res.body.remediation).toContain("Link a page only if you already know its route; do not search for one"); expect(res.body.remediation).not.toContain("](/"); }); diff --git a/server/src/routes/authz.ts b/server/src/routes/authz.ts index 27709a3b8c0..b0a64ec9a54 100644 --- a/server/src/routes/authz.ts +++ b/server/src/routes/authz.ts @@ -48,6 +48,7 @@ const AGENT_PROFILE_TABS: Record = { const BOARD_CONTROL_PAGES: Array<[RegExp, (match: RegExpExecArray) => [string, string]]> = [ [/^\/(?:companies\/[^/]+\/)?secrets?(?:[-/]|$)/, () => ["company secrets", "//company/settings/secrets"]], [/^\/companies\/[^/]+\/(?:budgets|budget-incidents|costs)(?:\/|$)/, () => ["budgets", "//activity/budgets"]], + [/^\/companies\/[^/]+\/(?:prompt-injection-prevention|decision-model|fast-response)(?:\/|$)/, () => ["connection settings", "//company/settings/connections"]], [/^\/companies\/[^/]+\/(?:members|invites|join-requests)(?:\/|$)/, () => ["company members", "//company/settings/members"]], [/^\/companies\/[^/]+\/(?:tools\/)?gateways(?:\/|$)|^\/tool-gateway\//, () => ["tool gateways", "//apps/gateways"]], [/^\/approvals\/([^/]+)/, match => ["the approval", `//approvals/${match[1]}`]], @@ -76,7 +77,7 @@ export function boardAccessRequired(req: Request) { const page = boardControlPage(req); const where = page ? `They can do it in the Paperclip web app: link [Open ${page[0]}](${page[1]}), with this conversation's company prefix as .` - : "They can do it in the Paperclip web app or with their own board credentials; link the most specific page you know."; + : "They can do it in the Paperclip web app or with their own board credentials. Link a page only if you already know its route; do not search for one."; return forbidden("Board access required", { code: BOARD_ACCESS_REQUIRED_CODE, remediation: `This action is board-only by design and this denial is final: no agent credential, tool or other API route can do it, so do not search for one. Tell the person that a board user must do it. ${where}`,