Role-based access control
with least privilege by default
Four workspace roles, thirty named permissions, and a single requirePermission gate on every privileged action. Members operate on findings and scans, admins manage the team, owners change billing and roles, viewers read only. Every transition lands on the activity log with the actor and the inputs.
No credit card required. Free plan available forever.
Least-privilege role-based access control built into the workspace
Internal security teams, AppSec teams, GRC and compliance teams, vulnerability management teams, and security service providers all carry the same problem the moment more than one person uses the platform. Findings, engagements, scans, credentials, and invoices all need to be created, edited, deleted, and reviewed by the right roles, and the wrong role on any of those surfaces is either a control gap the next audit will find or a friction point the team works around. SecPortal answers that problem with a fixed, well-typed role-based access control model: four workspace roles, thirty named permissions, and a single requirePermission gate that sits in front of every privileged action on the API.
The model is enforced in code, not in policy. A member who is not allowed to delete a client cannot delete a client at the API layer; the route returns a 403 before the database is touched. An admin who is not allowed to change billing cannot reach the Stripe surface. A viewer who is not allowed to write anything cannot write anything. The role on the team_members row is the single source of truth for what the actor is allowed to do, and every privileged action that succeeds writes an attributable line to the workspace activity log so the audit trail is the same artefact the operator reads day to day.
Four workspace roles, ordered by privilege
Viewer
Read-only access to the workspace data the role can already see.
Capabilities. Holds a single permission, view_data. A viewer reads engagements, findings, scans, documents, and the activity feed within the workspace, but cannot create, edit, or delete any record, run a scan, manage credentials, send an invoice, invite a client, or change any setting. The viewer role is the lowest tier of the four-role hierarchy and is the right shape for auditors, board observers, and read-only analysts who need to see the work without writing to it.
Right reader. Internal audit observers, board members reviewing programme posture, vendor risk reviewers, security analysts shadowing a workflow, and any reader who needs visibility without responsibility for the record.
Member
Day-to-day operator role for security testing and remediation work.
Capabilities. Carries 22 permissions covering client and engagement lifecycle, finding creation and editing, bulk import, document upload, invoice creation and sending, AI chat, AI report generation, client invitation, domain management, scan initiation, encrypted credential management, and repository connection management. A member does not have manage_team, change_roles, workspace_settings, billing, or delete permissions on clients or engagements, so the day-to-day operator surface is wide enough to run the work without holding the keys to the team or the billing account.
Right reader. Pentesters running engagements, AppSec engineers triaging scanner findings, vulnerability management operators routing findings to owners, security testers creating reports, and consultants delivering against client SOWs.
Admin
Team manager role that adds delete-class permissions and team management.
Capabilities. Carries 26 permissions: every member permission plus delete_client, delete_engagement, delete_invoice, manage_team, and change_roles. An admin can prune the client list, remove an engagement that should not have been created, void an invoice that was issued in error, invite or remove team members, and change roles up to admin. An admin cannot change billing or workspace settings and cannot promote a member to owner, so the team management surface is wide enough to run the team without reaching the contractual and financial controls owners hold.
Right reader. Security team leads, security operations managers, consulting practice leads, and engagement directors who need to manage the team and the engagement portfolio without controlling billing.
Owner
Full control of the workspace, including billing, settings, and role hierarchy.
Capabilities. Carries all 30 permissions including workspace_settings and billing. An owner holds the entire admin surface plus the contractual and financial controls. The platform allows exactly one owner per workspace, and the change_roles flow refuses to promote any member to owner via the standard team management endpoint so the owner seat is never duplicated by an admin acting in good faith. Transfer of the owner seat is a deliberate workspace event rather than an incidental team change.
Right reader. Workspace founders, security programme owners, CISOs accountable for the platform, and head-of-security roles who carry the billing relationship with SecPortal.
Thirty named permissions, grouped by the work they govern
The Permission union is defined in code and every privileged API route names the permission it requires. The grouping below mirrors how the team actually thinks about the work: client lifecycle, engagement lifecycle, finding lifecycle, evidence and import, invoicing, scanning, team management, and the workspace control plane.
View and read
view_data
The base permission every role holds. Without view_data a member cannot see the workspace data at all. Higher-tier permissions never imply read access; they extend the action surface on top of the read floor.
Client lifecycle
create_client, edit_client, delete_client
Member and above can create and edit client records. Delete is admin and owner only, so a member cannot accidentally remove a client and the engagements, findings, and invoices that hang off it.
Engagement lifecycle
create_engagement, edit_engagement, delete_engagement
Member and above can scaffold and edit engagements. Delete is admin and owner only, so the engagement record and its evidence trail cannot be removed by the day-to-day operator who runs the work.
Finding lifecycle
create_finding, edit_finding, delete_finding
Member, admin, and owner can create, edit, and delete findings. Finding deletion is intentionally inside the operator surface so a duplicate or accidentally created finding can be cleaned up without escalating to admin every time.
Bulk import and documents
bulk_import, upload_document, delete_document
Bulk import of Nessus, Burp Suite, and CSV findings is gated by bulk_import and held in member and above. Document upload and deletion attach evidence to engagements and findings; deletion is intentionally available to members so day-to-day file cleanup does not block on admin approval.
Invoicing
create_invoice, edit_invoice, delete_invoice, send_invoice
Members and above can create, edit, and send invoices. Delete is admin and owner only, so an issued invoice cannot be erased by the operator who created it; admin and owner carry the right to void.
AI and assistance
ai_chat, ai_reports
Member, admin, and owner can use the workspace AI assistant and the AI report generator. Viewer is excluded because both surfaces propose actions that write to the workspace, even when the final write is approved by the human in the loop.
Client portal and scanning
invite_client, manage_domains, initiate_scan, manage_credentials, manage_repos
Inviting client portal users, managing verified domains, initiating scans, managing encrypted credentials for authenticated scanning, and managing repository connections for code scanning are member and above. Verified domains and credentials carry their own security weight, so the requirePermission gate sits in front of every privileged write on those surfaces.
Team management
manage_team, change_roles
Inviting, removing, and changing the roles of workspace members is admin and owner only. The change_roles flow runs through canSetRole, which refuses to promote any member to owner via the standard API and refuses to let an admin act on an admin or owner target.
Workspace and billing
workspace_settings, billing
Workspace settings and the Stripe billing surface are owner only. The owner role exists to carry the contractual relationship with SecPortal and the policy decisions that apply to the whole workspace.
Role and permission matrix
A quick reference for every named permission against the four workspace roles. The matrix is generated from the same role definition file the API gate reads, so the table on the marketing page and the gate in production never diverge.
| Permission | Viewer | Member | Admin | Owner |
|---|---|---|---|---|
| view_data | Yes | Yes | Yes | Yes |
| create_client / edit_client | No | Yes | Yes | Yes |
| delete_client | No | No | Yes | Yes |
| create_engagement / edit_engagement | No | Yes | Yes | Yes |
| delete_engagement | No | No | Yes | Yes |
| create_finding / edit_finding / delete_finding | No | Yes | Yes | Yes |
| bulk_import | No | Yes | Yes | Yes |
| upload_document / delete_document | No | Yes | Yes | Yes |
| create_invoice / edit_invoice / send_invoice | No | Yes | Yes | Yes |
| delete_invoice | No | No | Yes | Yes |
| ai_chat / ai_reports | No | Yes | Yes | Yes |
| invite_client | No | Yes | Yes | Yes |
| manage_domains | No | Yes | Yes | Yes |
| initiate_scan | No | Yes | Yes | Yes |
| manage_credentials | No | Yes | Yes | Yes |
| manage_repos | No | Yes | Yes | Yes |
| manage_team / change_roles | No | No | Yes | Yes |
| workspace_settings | No | No | No | Yes |
| billing | No | No | No | Yes |
Where the gate runs in the stack
Roles are not a UI hint. The gate runs at the API and the database, and the dashboard only hides the controls the role is not allowed to use as a courtesy on top of the real enforcement layer.
- Every privileged API route calls requirePermission(role, "name") before any database write or external action runs
- requirePermission returns a 403 NextResponse with a uniform error body when the role lacks the named permission, so the failure mode is consistent across the API surface
- Role membership lives on the team_members row and is read once per request from the cached getAuthProfile helper, so the gate cannot be bypassed by switching the surface
- Roles compose with Supabase row-level security policies so the database returns only the rows the workspace member can see, even when an API caller bypasses the route handler
- Roles compose with workspace-enforced multi-factor authentication so a member cannot exercise their permissions until the session is promoted to AAL2
- Roles compose with the workspace activity log so every role change and every privileged action lands on an attributable, timestamped audit trail
Why this matters for internal security teams and enterprise buyers
Enterprise buyers, internal AppSec leads, GRC owners, vulnerability management programme leads, and CISOs evaluate security platforms against a procurement checklist that almost always includes least privilege, separation of duties, role auditability, and tenant isolation. The role layout below shows how SecPortal satisfies each item without relying on procedural discipline or external policy.
Least privilege by default
A new member is invited with the member role, not the admin role. The default is the day-to-day operator surface, and elevation to admin is a deliberate Settings change rather than an oversight. Viewers start at the lowest tier with a single view_data permission. The default posture for the whole workspace is the lowest practical privilege for the work the person actually carries.
Separation of duties between operator and team manager
The member surface is wide enough to run the work; the admin surface adds the delete-class actions and the team management surface; the owner surface adds workspace settings and billing. A single member cannot delete the client they invoiced, cannot remove themselves from the team, and cannot send themselves more permissions. Separation of duties between operator and team manager is enforced by the role layout rather than left to procedural discipline.
Auditable role changes
Every team membership and role change writes to the activity log with the actor, the target, the old role, and the new role. The audit trail is workspace-scoped and survives the next ISO 27001 surveillance, SOC 2 Type II window, or internal access review. Internal audit reads the same activity feed the operator reads, so the source of truth is one record rather than a reconciliation between three.
One owner seat per workspace
The platform enforces a single owner per workspace. The change_roles flow refuses to promote any member to owner via the standard endpoint, so an admin acting in good faith cannot accidentally create a second owner seat. Transfer of the owner seat is a deliberate, logged workspace event rather than an incidental role change.
Tenant isolation through the same role gate
Roles are scoped to a workspace. A member in one workspace is not a member in another workspace; team_members rows are workspace-scoped and the API gate reads the membership for the workspace the request is operating on. Cross-tenant elevation is impossible because the role lookup is bound to the tenant the caller is acting under.
Client portal lives outside the workspace role hierarchy
Client portal users hold the client role, which is separate from the four workspace roles. A client portal user reads only the findings, engagements, and documents tied to their own client record, with no path into the workspace role hierarchy. Workspace members and client portal users share notification and comment surfaces but never share role membership.
Roles compose with the rest of the security model
Role-based access control is one layer in the platform security model. The role gate answers who is allowed to take a given action; other layers answer whether the actor on the other end of the request is who the system expects, whether the action is recorded, and whether the data the action touches is isolated to the tenant. The composition is deliberate: a role on its own would not be enough, and the layers below would not be enough without a role gate to scope what each actor is allowed to do.
Workspace-enforced multi-factor authentication promotes the session to AAL2 before any role permission can be exercised. The middleware refuses to let an unverified factor through, so a stolen password cannot exercise a member role on its own. The role gate runs after the AAL2 check, so the identity is established before the permission is evaluated.
The workspace activity log records every role change with the actor, the target member, the old role, and the new role. Internal audit, ISO 27001 surveillance, and SOC 2 access review questions are answered from the same activity feed the operator reads, so the audit trail is one artefact rather than a reconciliation between three systems.
The team management surface is where roles are assigned at invite time and changed in Settings. The canSetRole helper refuses to let an admin promote any member to owner via the standard endpoint and refuses to let an admin act on an admin or owner target, so the role hierarchy is enforced in code rather than by hoping the admin remembers the policy.
Sensitive surfaces compose the role gate with their own security primitives. Encrypted credential storage for authenticated scanning is gated by manage_credentials and stored with AES-256-GCM authenticated encryption. Repository connections for code scanning are gated by manage_repos and bound to OAuth tokens encrypted at rest. Verified domain management is gated by manage_domains so a scan cannot be aimed at a target the workspace has not proved it owns.
The client portal sits outside the four workspace roles. Client portal users hold the client role and read only the findings, engagements, and documents tied to their own client tenant. The workspace role hierarchy never grants access into another client tenant, and the client role never grants access into the workspace dashboard, so the two surfaces share comments and notifications without ever sharing role membership.
The routing layer that decides which workspace the request belongs to before the role gate ever runs is documented on the tenant subdomain isolation feature page. The role gate trusts the resolved tenant: a member in workspace A cannot exercise permissions in workspace B because the middleware resolved the request to A, and the role lookup is scoped to A from that point onward.
Operationalising least privilege from day one
New workspaces start with one owner: the user who created the workspace. Every member added through the invite flow lands at the member role by default, which is the day-to-day operator surface rather than the team manager surface. Elevation to admin or a step down to viewer is a deliberate Settings change rather than an oversight. The role layout below is the recommended onboarding shape for an internal security team or a consulting practice running a multi-person workspace.
- Owner is the workspace creator or the head of programme who carries billing. Exactly one owner per workspace.
- Admin is the team lead, practice manager, or security operations manager who needs the delete-class actions and team management without billing or settings.
- Member is the day-to-day operator: pentester, AppSec engineer, vulnerability management operator, or security analyst running engagements and triaging findings.
- Viewer is the read-only observer: internal audit, board reviewer, vendor risk reviewer, or shadow analyst onboarding into the team.
- When a member leaves the team, the admin removes the row from team management; the activity log records the removal with actor and timestamp.
- When a quarterly access review runs, the admin reads the team_members table and the activity log; the audit answer is one query rather than a spreadsheet reconcile.
For the workflow that operationalises this model alongside the rest of the security testing programme, see the security testing programme management use case. For the evidence-collection side of the same audit answer, see the compliance audits use case.
The audience pages that map most closely to this role model are the internal security teams page, the GRC and compliance teams page, and the CISO page; each one frames the role and audit trail conversation in the language the respective buyer uses.
Give every member exactly the access they need
Roles are assigned at invite, changed in Settings, and gated at the API. The activity log records every role change with the actor and the timestamp so least privilege survives the next audit window.
No credit card required. Free plan available forever.