Security Audit
Scan the Stella codebase for security issues. We handle sensitive legal documents — security is non-negotiable.
Instructions
- Hardcoded secrets — scan for API keys, tokens, passwords, connection
strings in source files (not .env.example or .env):
Search for patterns like apiKey, secret, password, token, credential assigned to string literals in apps/ and packages/. Ignore markdown, example files, and node_modules.
- Auth bypass — verify that every handler in
apps/api/src/handlers/ checks authentication. Read each handler's route file and confirm auth middleware is applied. Flag any endpoint that is publicly accessible without explicit justification.
- Ownership via branded types — every workspace-scoped handler
must use createHandler from api-handlers.ts, which provides a WorkspaceHandlerContext with workspaceId: SafeId<"workspace">. Flag any handler that:
- Accepts
workspaceIdfrom the request body or query params
instead of the validated context
- Uses
createRootHandlerwhen it accesses workspace-scoped data - Passes a raw
stringwhereSafeId<"workspace">,
SafeId<"organization">, or SafeId<"user"> is expected
- Lacks a
permissionsdeclaration in itsconfig
- S3 presigned URLs — read
apps/api/src/handlers/files/presign.ts
and any other presign usage. Check that:
- Expiration is short (< 15 minutes for uploads, < 1 hour for reads)
- Workspace ownership is verified before generating presigned URLs
- No user input is passed unsanitised into S3 key paths (path
traversal via ../)
- File upload validation — check that uploaded files are validated
for type and size before being stored in S3. Verify that file metadata (content type, name) from the client is not blindly trusted.
- CORS configuration — read
apps/api/src/index.tsand check the
CORS setup. Flag origin: "*" or overly permissive origins. Should be restricted to your known domains.
- Dependency vulnerabilities:
If bunfig.toml configures a security scanner, run the configured Bun dependency scan:
``bash bun pm scan ``
If no scanner is configured, note that local Bun dependency scanning is unavailable for this repo and check the Dependabot alerts instead:
``bash gh api repos/{owner}/{repo}/dependabot/alerts --jq '.[].security_advisory.summary' ``
- AI prompt injection — check that user-provided content passed to
the AI SDK (Google Generative AI) is not interpolated directly into system prompts. Read the AI integration code in apps/api/src/ and verify that user content is clearly separated from system instructions.
- Workspace isolation — handlers must use
scopedDb(which
pre-filters by workspace) for all workspace-scoped queries. Flag any handler that:
- Uses the unscoped
dbdirectly for workspace-scoped tables - Constructs ad-hoc
WHERE workspaceId = ...instead of using
scopedDb
- Passes workspace IDs across handler boundaries without
re-validating ownership
- Ethical walls (information barriers) — in law firms, lawyers
working on opposing sides of a matter (or for competing clients) must not have access to each other's documents. Verify that:
- Matter-level access controls exist and are enforced at the query
level, not just the UI level
- File access checks the user's permission on the specific matter,
not just workspace membership
- Search results are filtered by matter access — a user must never
see documents from matters they are not assigned to
- AI features: see check #14 for detailed AI isolation requirements
- Presigned S3 URLs verify matter-level access, not just workspace
membership
- Audit logs capture who accessed what document and when (for
compliance evidence)
- If ethical wall / conflict check features exist, verify they
cannot be bypassed by direct API calls
- Auth and session management — the project uses better-auth with
organisation support, roles (Owner, Admin, Member), and email OTP. Check apps/api/src/lib/auth.ts and apps/api/src/db/auth-schema.ts. Verify that:
- Session tokens have a reasonable expiration
- Logout invalidates the session server-side (not just client-side)
- Role checks (Owner/Admin/Member) are enforced at the API level,
not just the UI
- Organisation membership is verified before granting access to
org resources
- Invitation tokens are single-use and expire
- OTP codes have rate limiting and short expiration
- A user removed from an organisation loses access immediately
(session is invalidated or next request is rejected)
- Data retention and deletion — when a document or matter is
deleted, verify that:
- The file is actually removed from S3, not just the DB reference
(no orphaned files)
- Or if soft-delete, that the file is inaccessible via presigned
URLs and excluded from search/AI context
- Deletion is logged for GDPR Article 17 compliance (right to
erasure — ability to prove data was deleted)
- Legal privilege leakage — attorney-client privilege and
work product doctrine mean document content must never leak through side channels:
- Search indexes, AI embeddings, and analytics events must
not contain document body text or metadata that reveals matter substance
- Error messages, logs, and stack traces must never include
document content, file names, or matter names (these can reveal case strategy)
- PDF thumbnails, preview images, and cached renders must
respect the same access controls as the source document
- Export and download endpoints must re-check permissions at
the moment of export, not rely on a stale permission grant
- Cross-matter data isolation in AI context — when AI
features (review, research, chat) build context:
- The context window must only include documents from
matters the requesting user has access to
- AI tool calls (
searchMatter,readEntity, etc.) must
enforce matter-level permissions per call, not per session
- AI-generated summaries, citations, or comparisons must
not reference documents from other matters, even if the model has seen them in a prior turn
- Conversation history must be scoped to the user and
matter; shared threads must not leak one user's queries to another
- Document versioning integrity — legal documents require
an unbroken chain of custody:
- Version history must be immutable: no endpoint allows
overwriting or deleting a prior version
- Version metadata (author, timestamp) must come from the
server, never from client-supplied values
- Concurrent edits to the same document must not silently
overwrite; verify optimistic locking or conflict detection is in place
- Audit trail completeness — SOC 2 and ISO 27001 require
evidence of who did what and when:
- All document access (view, download, print, share) must
produce an audit log entry, not just mutations
- Audit logs must be append-only; no endpoint allows
deletion or modification of log entries
- Bulk operations must log each affected resource
individually, not just "bulk action on N items"
- Audit log entries must include the actor's IP and
user-agent for forensic traceability
- Sensitive data in logs and errors — legal data requires
stricter controls than typical SaaS:
- Request/error logs must never contain document content,
file names, matter names, client names, or session tokens
- Structured logs must not serialize entire request bodies
(which may contain file contents or PII)
- Stack traces in production responses must be suppressed
(return generic