diff --git a/server/src/__tests__/authz-company-access.test.ts b/server/src/__tests__/authz-company-access.test.ts index 0928d62bbd2..b4b713592ad 100644 --- a/server/src/__tests__/authz-company-access.test.ts +++ b/server/src/__tests__/authz-company-access.test.ts @@ -46,6 +46,35 @@ describe("assertCompanyAccess", () => { expect(() => assertCompanyAccess(req, "company-1")).toThrow("Viewer access is read-only"); }); + it("rejects writes when membership details are present but omit the target company", () => { + const req = makeReq({ + method: "POST", + actor: { + type: "board", + userId: "user-1", + source: "session", + companyIds: ["company-1"], + memberships: [], + }, + }); + + expect(() => assertCompanyAccess(req, "company-1")).toThrow("User does not have active company access"); + }); + + it("allows legacy board actors that only provide company ids", () => { + const req = makeReq({ + method: "POST", + actor: { + type: "board", + userId: "user-1", + source: "session", + companyIds: ["company-1"], + }, + }); + + expect(() => assertCompanyAccess(req, "company-1")).not.toThrow(); + }); + it("rejects signed-in instance admins without explicit company access", () => { const req = makeReq({ method: "GET", diff --git a/server/src/routes/authz.ts b/server/src/routes/authz.ts index 5efa350ecff..ec6c49621dc 100644 --- a/server/src/routes/authz.ts +++ b/server/src/routes/authz.ts @@ -51,16 +51,12 @@ export function assertCompanyAccess(req: Request, companyId: string) { } const method = typeof req.method === "string" ? req.method.toUpperCase() : "GET"; const isSafeMethod = ["GET", "HEAD", "OPTIONS"].includes(method); - if (!isSafeMethod && !req.actor.isInstanceAdmin) { - const memberships = req.actor.memberships ?? []; - const membership = memberships.find((item) => item.companyId === companyId); - if (!membership) { + if (!isSafeMethod && !req.actor.isInstanceAdmin && Array.isArray(req.actor.memberships)) { + const membership = req.actor.memberships.find((item) => item.companyId === companyId); + if (!membership || membership.status !== "active") { throw forbidden("User does not have active company access"); } - if (membership?.status !== "active") { - throw forbidden("User does not have active company access"); - } - if (membership?.membershipRole === "viewer") { + if (membership.membershipRole === "viewer") { throw forbidden("Viewer access is read-only"); } }