Document management
for every security engagement
Upload SOWs, raw scanner exports, evidence captures, attestation letters, and post-engagement deliverables onto the engagement record. Storage is workspace-scoped, RBAC-gated, and recorded in the activity log so the chain of custody survives long after the work finishes.
No credit card required. Free plan available forever.
The engagement record holds the work, the findings, and the files that prove both
Security engagements produce documents at every stage. Pre-engagement: SOW, rules of engagement, kickoff deck, scope memo, target list, change orders. In-flight: raw scanner exports, reproduction screenshots, console captures, draft finding worksheets, customer evidence requests. Post-engagement: final report, executive summary, attestation letter, retest letter, closure letter, debrief deck, lessons learned. When those artefacts live in chat threads, personal drives, and email attachments, custody questions become forensic exercises and the next audit cycle starts from a blank page.
SecPortal stores engagement documents as a first-class object alongside findings and engagement records. Files are workspace-scoped and engagement-scoped, protected by row-level security on the table and the storage bucket, served only through signed URLs, validated for type and content at upload, and recorded in the activity log on every upload and delete. The platform stops being a place where the work happens and the files live somewhere else; it becomes the place where both live together.
How the storage is built
The storage layer is deliberately small. Files live in a private Supabase storage bucket, rows live in the documents table, and both share the workspace plus engagement scoping model. The properties below describe what the code actually enforces, not aspirational claims.
Engagement-scoped, workspace-scoped
Every document belongs to one engagement and one workspace. The storage path is workspaceId/engagementId/random-suffix-filename, so a file is reachable only through the engagement record it was uploaded against. Reassigning files between engagements is a deliberate, recorded action rather than a folder drag.
Row-level security on the documents table
The documents table has RLS enabled. Workspace operators read and write through a policy keyed to the workspace_id on their profile. Client portal users read and upload only against engagements they have explicit access to. A query that omits the workspace filter still returns nothing the caller is not authorised to see.
Storage RLS on the bucket
The Supabase storage bucket carries its own row-level policies that mirror the database. Operators can upload, read, and remove inside their own workspace path; client users can upload only inside engagements they belong to. Storage and database authorisation share a single tenant model rather than living on parallel tracks.
Signed URLs for every download
Files are never publicly readable. Every download or in-browser view is served through a signed URL with a short expiry, so a leaked link does not become a permanent disclosure. The bucket itself is private and clients have no direct token to browse it.
Filename sanitisation and content validation
Uploads pass through filename sanitisation that strips path traversal sequences and reserved characters, an extension allowlist, a MIME-type allowlist, and a magic-number check that confirms the file content matches the declared type. A renamed binary cannot smuggle its way past the extension check.
Per-file size cap and per-user rate limit
Single uploads are capped at fifty megabytes. The upload endpoint applies a per-user rate limit of thirty uploads per fifteen minutes, so a stolen session cannot bulk-stuff a workspace with files. Plan-level storage caps still apply on top of the per-file ceiling.
Accepted file types
The upload API accepts the document shapes a typical security engagement actually produces. Other types are rejected with a clear error rather than silently coerced, so the team learns the boundary at upload time instead of finding out at retest.
Scanner reports exported as PDF, signed SOWs, attestation letters, RFP responses, executive summaries, customer-supplied policies, and audit packs. The most common engagement document shape and the canonical archival format.
Word and Excel (DOC, DOCX, XLS, XLSX)
Editable scope drafts, redlined SOWs, change orders, finding worksheets, exception registers, evidence trackers, and any spreadsheet-driven artefact the team is still iterating on before it becomes a PDF.
CSV and plain text
Scanner exports, asset inventories the client supplied, host lists, IP ranges, vulnerability backlogs migrated from another tool, and any tabular artefact that needs to live with the engagement rather than in a side spreadsheet.
Images (PNG, JPG, JPEG, WEBP)
Reproduction screenshots, console captures, network diagrams, exploit chain diagrams, photo evidence for physical engagements, and any visual artefact attached to a finding or stored as supporting evidence on the engagement.
Lifecycle, end to end
A document moves through five stages from upload to retention. Each stage is small enough that the boundary between application code, database, storage, and the audit record is easy to inspect.
- A workspace operator with the upload_document permission attaches a file from the engagement screen, or a client portal user uploads a file against an engagement they have access to. The file is sanitised, validated, sized, and rate-limited at the API boundary before it reaches storage.
- The documents row is inserted with the workspace_id, engagement_id, file path, byte size, MIME type, the actor user ID, and a creation timestamp. The Postgres trigger fires document.uploaded into the activities feed with the file name, the engagement, the client, and resolved actor info.
- The file is reachable through the engagement screen for everyone the engagement scope allows. Downloads and in-browser previews use a fresh signed URL each time, not a permanent link, so revoked access cuts off retrieval immediately.
- A workspace operator with the delete_document permission removes the file. The storage object is removed, the documents row is deleted, the cascade preserves referential integrity against the engagement, and the trigger writes document.deleted into the activities feed with the same metadata shape.
- The activity feed retains the upload and delete events for the plan window (thirty days on Starter, ninety days on Pro, one year on Team). The custody chain is reviewable for the retention window of the workspace plan, not just for as long as the file itself exists.
Access control: who can move files
Storing files safely is half the problem. The other half is making sure only the right people can add and remove them, and that the actions are reviewable later. SecPortal handles both through team management with RBAC and multi-factor authentication rather than a parallel access model.
- Workspace owners, admins, and members hold the upload_document and delete_document permissions, so most operators on the workspace can manage engagement files.
- Workspace viewers and billing-only roles do not hold those permissions, so read-only stakeholders cannot move or remove documents they happen to see on the engagement.
- Client portal users can upload only against engagements they have been linked to through client_users. They can delete only files they themselves uploaded; they cannot remove files the workspace operators added.
- Workspace MFA enforcement promotes sessions to AAL2 before the dashboard becomes reachable, so document mutations inherit the same second-factor requirement as the rest of the workspace.
- Every upload and every delete is attributed to the acting user inside the activity record. There is no anonymous file move; the actor identity is part of the audit row.
Storage caps and the storage add-on
Document storage is plan-aware. The cap protects the workspace from runaway storage costs and gives the team a clear budget to plan retention against, with a paid add-on for cases where the volume genuinely exceeds the plan ceiling.
- Starter workspaces have a one gigabyte storage cap across all engagements. Suitable for a small backlog of evidence and scanner exports.
- Pro workspaces have a twenty-five gigabyte storage cap. Suitable for an active testing program with several engagements running concurrently.
- Team workspaces have a one hundred gigabyte storage cap. Suitable for a multi-team operation with long-running engagements and full historical retention.
- All plans accept the storage add-on. Extra storage is added in gigabyte increments and applied to the workspace cap, so a busy quarter does not require a plan upgrade.
- The upload API rejects writes that would exceed the plan-plus-add-on cap with a clear error rather than failing partway through and leaving the storage object orphaned.
How the activity log carries custody
Every upload and every delete writes a row into the activities feed through a Postgres trigger. The metadata captures the file name, the engagement, the client, and the resolved actor identity, so a custody question resolves to a single record rather than a forensic reconstruction. The same activity log carries findings, engagements, scans, comments, invoices, and team changes, so document events sit on the same timeline as the work they support.
For the longer-form discipline of how document evidence ages and when it stops being useful, see the research on the half-life of audit evidence, and pair it with the audit evidence tracker for a programme-level ledger that survives any one engagement.
Four document shapes a security engagement produces
The shape of the artefacts changes across the engagement lifecycle, but the storage model stays the same. The categories below cover the documents that actually accumulate against a typical security engagement.
Pre-engagement artefacts
Signed SOW, kickoff deck, rules of engagement, scope memo, target list, change orders, customer-supplied asset inventory, and authentication credentials handover summary. Everything the engagement scopes itself against lives on the same record the engagement runs from.
In-flight evidence
Scanner exports (Nessus .nessus files, Burp .xml output, custom CSV), reproduction screenshots, console captures, exploit chain diagrams, draft finding worksheets, and any other operating artefact captured during testing. The evidence stays attached to the engagement that produced it instead of drifting to a personal folder.
Deliverables and attestations
Final pentest reports, executive summaries, attestation letters, retest letters, closure letters, and any client-facing PDF generated outside or inside SecPortal. Storing them on the engagement record means the next audit cycle can find them without a treasure hunt.
Post-engagement artefacts
Customer feedback memos, debrief deck, lessons learned, retest evidence, and any document that supports the closed engagement. Together with the immutable activity record they form the historical case file for the engagement.
Questions an enterprise reviewer should be able to answer in five minutes
Procurement and security architecture reviews ask the same questions about any tool that holds engagement files. The system is built so the answers come from the engagement screen and the activity log rather than from inference.
- Which documents are attached to this engagement, who uploaded each one, and on which date?
- Was the executive deliverable for engagement X uploaded before or after the report was sent to the client?
- When was the raw scanner export for finding Y attached to the record, and is it still present?
- Which client portal users have uploaded files against engagements in the last ninety days, and what files did they upload?
- Was a sensitive document removed from this engagement, and if so by whom and when?
- Does the activity log retention window for the current plan still cover the upload event for the document an auditor is asking about?
Boundaries: what document storage is and what it is not
Document management is one capability inside a larger workspace, not a parallel content platform. Naming the boundary up front is the easiest way to keep the storage layer focused on its job and to point teams at the right tool when they reach the edge.
Do
Attach raw scanner exports, signed SOWs, executive summaries, and reproduction evidence to the engagement record so the audit trail and the deliverable share one source of record.
Do
Use the activity log filter for documents to answer custody questions, then use the engagement screen to confirm the file is still attached and accessible.
Do not
Use document storage as a credential vault. Authenticated scanner secrets belong in the encrypted credential vault, not in a CSV or DOCX attached to the engagement.
Do not
Treat signed-URL downloads as long-lived links. Each signed URL expires; share the engagement record with the recipient and let them generate a fresh download URL through the platform.
Where document management fits in the rest of the platform
Document storage exists to support the work the rest of the platform does. It carries the evidence behind pentest evidence management, holds the deliverables produced through pentest report delivery, and feeds the artefact list a compliance audit produces, so the engagement record stays the source of record from kickoff to attestation.
Sensitive scanner secrets do not belong in document storage. Authenticated scanner credentials live in the dedicated encrypted credential storage vault, which uses authenticated encryption and a different access model. Scanner output files (Nessus, Burp, CSV exports) are still safe to attach as documents because they describe findings, not secrets.
For the buyer-side framing of who runs this discipline, see the audience pages for internal security teams, GRC and compliance teams, and vulnerability management teams. Each one runs the document discipline against a different operating cadence, and the storage model stays the same underneath.
Stop scattering engagement files across email and shared drives
Attach every artefact to the engagement record. Audit answers come from one place, not five.
No credit card required. Free plan available forever.