Skip to content

Security: rciesco805/Secure-document-vault

SECURITY.md

Security Policy

Overview

BF Fund Investor Dataroom is designed with security as a core principle. This document outlines implemented security controls, known limitations, and vulnerability reporting procedures.

Supported Versions

Version Supported
1.x.x

Reporting a Vulnerability

If you discover a security vulnerability, please report it responsibly:

  1. Do NOT create a public GitHub issue
  2. Email security concerns to: [email protected]
  3. Include:
    • Description of the vulnerability
    • Steps to reproduce
    • Potential impact assessment
    • Any suggested remediation

We aim to respond within 48 hours and will work with you to understand and address the issue.

Operational Requirements

Before deploying, ensure:

  • TLS Termination: Deploy behind a reverse proxy or edge provider that enforces HTTPS (e.g., Vercel, Cloudflare, AWS ALB)
  • Environment Variables: Configure all required secrets via secure secret management

Implemented Security Controls

Transport Security

  • TLS: Requires deployment behind TLS-terminating proxy (application does not handle TLS directly)
  • HSTS: Strict-Transport-Security header set in production responses - see lib/middleware/csp.ts:153-157

Authentication & Authorization

Implemented:

  • NextAuth.js: Database-backed sessions with secure cookies
  • Magic Links: Email-based authentication for LP users
  • Google OAuth: Admin/GP authentication
  • Session Security (verified in lib/auth/auth-options.ts):
    • HttpOnly cookies
    • Secure flag (HTTPS only)
    • SameSite=None for cross-site/iframe compatibility (updated February 2026)

Role-Based Access Control:

  • LP (Limited Partner): Access to personal documents, subscriptions, portal
  • GP (General Partner): Fund management, investor oversight
  • Admin: Full platform access, user management
  • Viewer: Read-only document access

SSO Configuration (February 2026):

  • Supported providers: SAML 2.0, OIDC, Azure AD, Okta, Google Workspace
  • Organization-level SSO configuration stored in Organization.ssoConfig
  • Sensitive SSO credentials encrypted via OrganizationIntegrationCredential
  • Certificate/private key storage with AES-256-GCM encryption

Organization Security Policies:

  • OrganizationSecurityPolicy model enforces tenant-wide security:
    • MFA requirements (requireMfa)
    • Session timeout configuration
    • IP allowlist/denylist
    • Allowed authentication providers
    • Document watermarking requirements
    • Lockable policy keys (prevent override at fund/object level)

Defaults Inheritance Hierarchy:

  • Organization Defaults → Team Defaults → Fund/Dataroom/Link Settings
  • OrganizationDefaults auto-applied to new teams and objects
  • TeamDefaults optionally override organization-level settings
  • Lockable keys prevent fund/object-level overrides for critical security settings

Data Encryption

Implemented (ENABLED BY DEFAULT when key is configured):

  • Server-Side Encryption: AES-256-GCM encryption in storage pipeline - see lib/storage/encryption/crypto-service.ts
  • Encryption Key: Requires STORAGE_ENCRYPTION_KEY environment variable (64-character hex string)
  • Default Behavior: When encryption key is set, ALL files are encrypted by default
    • Use { encrypt: false } to explicitly store unencrypted (not recommended)
  • Key Generation: Run npm run generate:encryption-key to create a secure key

Production Security:

  • Password-derived keys are BLOCKED in production (NODE_ENV=production)
  • Only proper 64-character hex keys (256-bit) are accepted in production
  • Generate keys with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

PDF-Level Encryption (Implemented):

  • See lib/crypto/pdf-encryption.ts for AES-256 PDF 2.0 encryption using pdf-lib-plus-encrypt
  • Supports user/owner passwords, permission controls, and watermarking
  • Used for completed signature documents

Not Yet Implemented:

  • Client-side encryption before upload

Integration Credential Encryption (February 2026):

  • OrganizationIntegrationCredential model stores API keys and secrets
  • AES-256-GCM encryption using STORAGE_ENCRYPTION_KEY
  • Credential service: lib/organization/credential-service.ts
  • Per-credential integrity hash for tamper detection
  • Automatic key rotation tracking via lastRotatedAt

Content Security Policy (CSP)

Implemented (see lib/middleware/csp.ts):

  • Nonce-based script execution
  • Strict domain whitelisting for scripts, connections, images
  • Frame-ancestors restrictions (DENY by default)
  • WASM support for PDF processing

Security Headers

Implemented (see lib/middleware/csp.ts):

Header Value Status
Content-Security-Policy Nonce-based
X-Content-Type-Options nosniff
X-Frame-Options DENY / SAMEORIGIN
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy camera=(), microphone=(), geolocation=()
Strict-Transport-Security max-age=31536000; includeSubDomains; preload

Input Validation & Sanitization

Implemented:

  • sanitize-html (lib/utils/sanitize-html.ts): Strips all HTML tags from user content
    • Used in: team name updates, branding settings, agreements, conversation features
  • Path sanitization (proxy.ts:53-58): Removes .. sequences and normalizes slashes
  • Host validation (proxy.ts:19-29): Validates host format and length
  • IP validation (proxy.ts:31-47): Validates client IP format (IPv4/IPv6)
  • URL validation (lib/notion/utils.ts): Domain allowlist for external URLs
    • Blocks path traversal sequences (.., null bytes)
    • Enforces HTTPS protocol
    • Only allows known Notion domains
  • File path canonicalization (lib/storage/providers/local-provider.ts):
    • URL decoding before validation
    • Repeated .. sequence removal
    • path.resolve() + boundary checking
    • Throws error if path escapes storage directory

Audit Logging

Schema (see prisma/schema.prisma lines 1298-1318):

  • AuditLog model fields: id, eventType, userId, teamId, resourceType, resourceId, ipAddress, userAgent, metadata, createdAt
  • Indexed on: teamId, userId, eventType, createdAt

Usage locations:

  • Fund settings: pages/api/funds/[fundId]/settings.ts
  • Transactions: pages/api/transactions/index.ts
  • Data import/export: pages/api/admin/import.ts, pages/api/admin/export.ts

Retention Policy (Implemented February 2026):

Audit log retention is managed via environment variables and a cron job at /api/cron/audit-retention:

Log Type Retention (Days) Environment Variable
AuditLog 2555 (7 years) AUDIT_LOG_RETENTION_DAYS
SignatureAuditLog 2555 (7 years) SIGNATURE_AUDIT_LOG_RETENTION_DAYS
  • Default: 7 years (2555 days) - meets SEC/FINRA record retention requirements
  • Check Status: GET /api/cron/audit-retention returns current counts
  • Manual Cleanup: POST /api/cron/audit-retention runs the cleanup job

Limitations:

  • Logs stored in standard PostgreSQL tables (not immutable append-only storage)
  • For regulatory compliance, consider external append-only storage

Known Vulnerabilities

Current npm Audit Status (February 2026)

As of this writing, npm audit reports 1 vulnerability:

Moderate (1) - ESLint 8.x Stack Overflow:

  • Dependency chain: eslint-config-next -> [email protected]
  • Risk Acceptance: Development-only tool, not included in production builds

Status:

  • All critical and high vulnerabilities have been resolved
  • ESLint 8.x vulnerability accepted (dev-only, no production impact)
  • Run npm audit to verify current status before deployment

File Upload Security (Updated February 2026)

Path Traversal Protection

All file upload and storage operations are protected against path traversal attacks:

File Protection Method
lib/storage/providers/local-provider.ts URL decoding, null byte removal, repeated .. removal, path.resolve() canonicalization, boundary checking
pages/api/file/replit-upload.ts crypto.randomUUID() + character sanitization ([^a-zA-Z0-9.-]_)
pages/api/file/browser-upload.ts Vercel Blob with addRandomSuffix: true
pages/api/file/image-upload.ts Vercel Blob with addRandomSuffix: true
pages/api/file/s3/multipart.ts slugify() + teamId/docId directory structure
lib/files/put-file-server.ts slugify() + generated document IDs (newId)
lib/notion/utils.ts validateNotionMediaUrl() with domain allowlist, HTTPS enforcement

Storage Key Pattern

All files use safe generated keys: {teamId}/{docId}/{uuid}-{sanitizedName}

  • Never uses raw user-provided filenames as storage keys
  • Original filename stored in Document model metadata only
  • Keys are structured to prevent cross-tenant access

Security Controls by Provider

Provider Key Generation Validation
Replit Object Storage {PRIVATE_OBJECT_DIR}/documents/{docId}/{safeName} UUID prefix, slugified name
S3/R2 {teamId}/{docId}/{slugifiedName} Team isolation, slugified name
Vercel Blob Auto-generated with random suffix SDK-managed
Local Filesystem Path canonicalization + boundary check Throws on traversal attempt

Additional Protections

  • Filename sanitization: Non-alphanumeric characters replaced with underscores or slugified via @sindresorhus/slugify
  • Content-type validation: Based on file extension and MIME type with allowlists
  • Encrypted storage: Enabled by default when STORAGE_ENCRYPTION_KEY is configured
  • Size limits: Enforced per upload endpoint (100MB max for documents, 5MB for images)
  • Allowed file types: Strict MIME type allowlists per endpoint

Not Yet Implemented

  • Virus scanning integration (ClamAV or cloud-based)
  • File content verification beyond extension/MIME type
  • Magic byte validation for uploaded files

506(c) Compliance

Implemented:

  • Accreditation self-certification wizard
  • Persona KYC/AML integration hooks (sandbox/production modes)
  • Audit logging for verification steps

Audit Trail Contents:

  • Timestamp (UTC)
  • User ID
  • Action type
  • IP Address
  • User Agent

Data Retention Guidelines

Recommended retention periods for compliance:

Data Type Recommended Retention Notes
Audit Logs 7 years SEC/FINRA compliance
Investor Documents Fund lifetime + 7 years Legal/tax requirements
Session Data 30 days Automatic expiry
KYC/AML Records 5 years post-relationship AML regulations

Note: Actual retention is dependent on database backup and deletion policies configured by the operator.

Dependency Management

Recommended Practices

  • Run npm audit before deployments
  • Enable Dependabot or similar for automated alerts
  • Review and update dependencies monthly

Vulnerability Response Guidelines

  • Critical: Patch within 24 hours
  • High: Patch within 7 days
  • Moderate: Patch within 30 days
  • Low: Patch in next release

Development Security

Code Review

  • All changes should require pull request review
  • Security-sensitive changes should have additional scrutiny

Secrets Management

  • No secrets in code repository
  • Use environment variables for configuration
  • Use Replit Secrets or similar secure storage for sensitive values

Security Hardening Guide

Secrets Rotation Schedule

Secret Rotation Frequency Impact
NEXTAUTH_SECRET Quarterly Invalidates all sessions
STORAGE_ENCRYPTION_KEY Annually Requires re-encryption
Database password Quarterly Connection string update
PLAID_SECRET As needed Regenerate in dashboard
STRIPE_SECRET_KEY As needed Regenerate in dashboard
PERSONA_API_KEY As needed Regenerate in dashboard

Rotation Procedure:

  1. Generate new secret value
  2. Update in environment (Replit Secrets or .env.local)
  3. Deploy/restart application
  4. Monitor logs for authentication errors
  5. Document rotation date

Rate Limiting (Implemented)

Rate limiting is implemented using lib/security/rate-limiter.ts with three tiers:

Limiter Limit Window Use Case
authRateLimiter 10 requests 1 hour Authentication endpoints
strictRateLimiter 3 requests 1 hour Sensitive operations
apiRateLimiter 100 requests 1 minute General API endpoints

Protected Endpoints:

  • /api/auth/admin-magic-verify - Admin magic link verification (auth limiter)
  • /api/view/verify-magic-link - Magic link verification (auth limiter)
  • /api/request-invite - Invite requests (strict limiter)
  • /api/lp/complete-gate - LP onboarding (api limiter)
  • /api/sign/* - Signature endpoints (10-30 req/min via Redis ratelimit)

Violations are logged to the SignatureAuditLog table for security monitoring.

CORS Configuration (Recommended - Not Yet Implemented)

For production deployments requiring cross-origin API access, add CORS headers in next.config.mjs:

// Example configuration - add to next.config.mjs if needed
async headers() {
  return [
    {
      source: '/api/:path*',
      headers: [
        { key: 'Access-Control-Allow-Origin', value: process.env.NEXTAUTH_URL },
        { key: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,DELETE,OPTIONS' },
        { key: 'Access-Control-Allow-Headers', value: 'Content-Type,Authorization' },
        { key: 'Access-Control-Max-Age', value: '86400' },
      ],
    },
  ];
}

Note: The application currently uses same-origin requests. Configure CORS only if you need cross-origin API access.

Backup Strategy

Database Backups:

  • Daily automated backups (retain 30 days)
  • Weekly backups (retain 1 year)
  • Point-in-time recovery enabled

File Storage Backups:

  • S3/R2: Enable bucket versioning
  • Local: Daily compressed archives

Backup Verification:

  • Monthly restore tests
  • Documented recovery procedure

See docs/DEPLOYMENT.md for detailed backup scripts.

Recommended Enhancements

The following security improvements are recommended but not yet implemented:

  1. Virus Scanning: Integrate file scanning for uploads
  2. Client-Side Encryption: Encrypt sensitive data before transmission
  3. Immutable Audit Logs: Use append-only storage for compliance
  4. Penetration Testing: Conduct quarterly security assessments

Contact

For security inquiries:

For general support:

There aren’t any published security advisories