Severity: Medium
Area: Web — authorization / audit
Location
web/src/app/api/workspaces/[workspace]/audit/export/route.ts:50-57
Problem
The audit-log export gates only on userIsMember, not on a role. The code's own TODO(US-0.4-02) acknowledges RBAC isn't enforced yet:
const ok = await userIsMember(workspace.id, session.user.id);
if (!ok) { ... 403 ... }
// TODO(US-0.4-02): swap to requireWorkspaceRole(>= viewer) once RBAC lands.
Why it matters
Any member (the lowest privilege) can download up to 10,000 audit rows for the whole workspace — other members' actions, connection authorizations, secret-rotation events, improvement text. That's the full governance trail, exfiltrable by a low-trust member.
Suggested fix
Gate on the appropriate role (authorizeWorkspace(slug, "viewer"/"auditor")) per the stated acceptance criteria, matching the connection routes.
Severity: Medium
Area: Web — authorization / audit
Location
web/src/app/api/workspaces/[workspace]/audit/export/route.ts:50-57Problem
The audit-log export gates only on
userIsMember, not on a role. The code's ownTODO(US-0.4-02)acknowledges RBAC isn't enforced yet:Why it matters
Any member (the lowest privilege) can download up to 10,000 audit rows for the whole workspace — other members' actions, connection authorizations, secret-rotation events, improvement text. That's the full governance trail, exfiltrable by a low-trust member.
Suggested fix
Gate on the appropriate role (
authorizeWorkspace(slug, "viewer"/"auditor")) per the stated acceptance criteria, matching the connection routes.