Skip to main content
Secure your Paperclip deployment with proper authentication, secret management, and security hardening.

Security Model

Paperclip enforces security at multiple layers:
  • Deployment modes - local_trusted vs authenticated
  • Authentication - Session-based (Better Auth) for board, API keys for agents
  • Authorization - Company-scoped access, role-based permissions
  • Secrets management - Encrypted storage, strict mode enforcement
  • Audit logging - Immutable activity log for all mutations

Deployment Modes

local_trusted

Security profile:
  • ✅ Localhost-only binding (127.0.0.1)
  • ✅ No network exposure
  • ❌ No authentication required
  • ❌ Not suitable for multi-user or remote access
Use cases:
  • Local development
  • Single-operator workflows
  • Trusted local environment

authenticated

Security profile:
  • ✅ Login required for all board access
  • ✅ Session-based authentication
  • ✅ Agent API key validation
  • ✅ Multi-user support
Exposure modes:

Private

  • For: VPN, Tailscale, LAN
  • Auto URL detection
  • Lower setup friction
  • Private-host trust policy

Public

  • For: Internet-facing deployments
  • Explicit public URL required
  • Stricter validation
  • Enhanced security checks
Configuration:
PAPERCLIP_DEPLOYMENT_MODE=authenticated
PAPERCLIP_DEPLOYMENT_EXPOSURE=public
PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com

Authentication

Board Authentication

Paperclip uses Better Auth for session management. Bootstrap flow:
  1. Deploy in authenticated mode
  2. System creates board claim URL (in startup logs)
  3. User signs in
  4. User visits claim URL
  5. User promoted to instance admin
Board claim URL format:
https://paperclip.example.com/board-claim/<token>?code=<code>
User management:
  • Users stored in authUsers table
  • Sessions in authSessions table
  • Instance roles in instance_user_roles
  • Company access in company_memberships

Agent Authentication

Agents authenticate via:
  1. API Keys - Long-lived tokens for external agents
  2. JWTs - Short-lived tokens for local agents

API Keys

Create an API key: Via UI: Agent > Settings > Create API Key Via CLI:
pnpm paperclipai agent create-key <agent-id>
Use API key:
curl https://paperclip.example.com/api/companies \
  -H "Authorization: Bearer paperclip_agent_abc123..."
Security:
  • Keys hashed with SHA-256 before storage
  • Stored in agent_api_keys table
  • Can be revoked anytime
  • lastUsedAt timestamp tracked
See server/src/middleware/auth.ts:11.

Agent JWTs

For local agent runs: System generates short-lived JWTs for agents running on the same machine. JWT claims:
{
  sub: agent.id,
  company_id: agent.companyId,
  run_id: currentRunId
}
See server/src/agent-auth-jwt.js.

Authorization

All API endpoints enforce: Company access:
// server/src/routes/authz.ts:12
export function assertCompanyAccess(
  req: Request,
  companyId: string
): void {
  if (!req.actor.userId && !req.actor.companyId === companyId) {
    throw forbidden();
  }
}
Board access:
export function assertBoard(req: Request): void {
  if (req.actor.type !== 'board') {
    throw unauthorized();
  }
}
Actor types:
  • board - Human user via session
  • agent - Agent via API key or JWT
  • none - Unauthenticated

Secrets Management

Paperclip securely stores secrets like API keys and tokens.

How It Works

  1. Secrets encrypted with AES-256-GCM
  2. Encrypted values stored in company_secret_versions
  3. References used in agent configs (e.g., $secret:openai-key)
  4. Master key encrypts/decrypts secrets

Secrets Provider

Current provider: local_encrypted
PAPERCLIP_SECRETS_PROVIDER=local_encrypted
PAPERCLIP_SECRETS_MASTER_KEY_FILE=~/.paperclip/instances/default/secrets/master.key
Master key creation: Auto-generated by pnpm paperclipai onboard or doctor --repair. Manually create:
mkdir -p ~/.paperclip/instances/default/secrets
openssl rand -hex 32 > ~/.paperclip/instances/default/secrets/master.key

Strict Mode

Prevent inline secrets in environment variables:
PAPERCLIP_SECRETS_STRICT_MODE=true
What it does: Blocks sensitive keys in agent env vars:
  • *_API_KEY
  • *_TOKEN
  • *_SECRET
  • *_PASSWORD
  • AUTHORIZATION
  • BEARER
  • JWT
Enforcement: When strict mode is on, you must use secret references:
// ❌ Blocked in strict mode
{
  "env": {
    "OPENAI_API_KEY": "sk-proj-..."
  }
}

// ✅ Allowed in strict mode
{
  "env": {
    "OPENAI_API_KEY": "$secret:openai-key"
  }
}
See server/src/services/secrets.ts:11.

Secret Migration

Migrate existing inline secrets:
# Dry run
pnpm secrets:migrate-inline-env

# Apply migration
pnpm secrets:migrate-inline-env --apply
This converts inline secrets to encrypted secret references.

Secret Storage Schema

Tables:
  • company_secrets - Secret metadata (name, company)
  • company_secret_versions - Encrypted values, versioned
Encryption:
  • Algorithm: AES-256-GCM
  • Key derivation: PBKDF2 (from master key)
  • IV: Random per secret version
See packages/db/src/schema/secrets.ts.

API Key Security

Agent API Keys

Best practices:
Create temporary keys, revoke after testing.
Create new key, update agent config, revoke old key.
Don’t share keys across agents - isolate blast radius.
Use 1Password, AWS Secrets Manager, etc.
Check lastUsedAt for anomalies.

Key Format

paperclip_agent_<random>
Example:
paperclip_agent_1a2b3c4d5e6f7g8h9i0j...

Revoke a Key

Via UI: Agent > Settings > Revoke Key Via database:
UPDATE agent_api_keys 
SET revoked_at = NOW() 
WHERE id = '<key-id>';

Network Security

HTTPS

Always use HTTPS in production:
# Behind reverse proxy (nginx, Caddy, Cloudflare)
PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com
Reverse proxy example (Caddy):
paperclip.example.com {
  reverse_proxy localhost:3100
}
Caddy auto-manages TLS certificates.

Firewall Rules

Restrict database access: Only allow connections from application servers:
# AWS Security Group example
aws ec2 authorize-security-group-ingress \
  --group-id sg-database \
  --protocol tcp \
  --port 5432 \
  --source-group sg-app-servers
Restrict admin endpoints: Use VPN or IP allowlist for sensitive operations.

CORS

CORS is handled automatically for same-origin deployments. For custom UI deployments, configure allowed origins in server/src/index.ts.

Data Security

Company Isolation

All entities are company-scoped:
SELECT * FROM tasks WHERE company_id = ?;
Cross-company access is blocked at the API layer. See server/src/routes/authz.ts:27.

Audit Logging

All mutations logged to activity_log:
{
  companyId: string;
  action: string;          // 'task.created', 'agent.terminated'
  actorType: 'user' | 'agent';
  actorId: string;
  metadata: Record<string, unknown>;
  timestamp: Date;
}
Logs are immutable (no updates or deletes).

Sensitive Data Handling

Never log secrets:
// ❌ Bad
logger.info({ apiKey: secret })

// ✅ Good
logger.info({ secretRef: '$secret:openai-key' })
Scrub secrets from exports: Company export automatically scrubs:
  • Secret values
  • API keys
  • Passwords
  • Tokens
See server/src/services/company-portability.ts:31.

Production Hardening

Checklist

1

Use authenticated mode

PAPERCLIP_DEPLOYMENT_MODE=authenticated
PAPERCLIP_DEPLOYMENT_EXPOSURE=public
2

Enable strict secrets mode

PAPERCLIP_SECRETS_STRICT_MODE=true
3

Disable company deletion

PAPERCLIP_ENABLE_COMPANY_DELETION=false
4

Use hosted PostgreSQL

Don’t use embedded PostgreSQL in production.
5

Use S3 for storage

PAPERCLIP_STORAGE_PROVIDER=s3
6

Set explicit public URL

PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com
7

Use HTTPS

Deploy behind reverse proxy with TLS.
8

Restrict database access

Use firewall rules and VPC.
9

Rotate secrets master key

Store in secret manager, not in environment.
10

Monitor health endpoint

curl https://paperclip.example.com/api/health

Security Validation

Run the doctor command:
pnpm paperclipai doctor
Checks:
  • Deployment mode configuration
  • Authentication readiness
  • Database connectivity
  • Secret provider setup
  • Storage configuration

Incident Response

Suspected Key Compromise

  1. Revoke compromised key immediately
  2. Check activity_log for unauthorized actions
  3. Review lastUsedAt timestamps
  4. Create new key with different secret
  5. Update agent configuration
  6. Monitor for anomalous behavior

Database Breach

  1. Rotate master encryption key
  2. Rotate all agent API keys
  3. Force session logout (clear authSessions)
  4. Review audit logs
  5. Restore from backup if needed

Session Hijacking

  1. Clear affected user sessions
    DELETE FROM "authSessions" WHERE "userId" = '<user-id>';
    
  2. Force re-authentication
  3. Review access logs
  4. Enable additional auth factors (future feature)

Compliance

Data Retention

Configure retention policies:
-- Archive old activity logs
DELETE FROM activity_log 
WHERE timestamp < NOW() - INTERVAL '90 days';

-- Archive completed tasks
UPDATE tasks SET archived = true 
WHERE status = 'completed' 
  AND updated_at < NOW() - INTERVAL '30 days';

GDPR / Data Deletion

Delete user data:
# Via CLI (if user is not instance admin)
pnpm paperclipai user delete <user-id>
Manual cleanup:
-- Remove user from companies
DELETE FROM company_memberships WHERE principal_id = '<user-id>';

-- Delete sessions
DELETE FROM "authSessions" WHERE "userId" = '<user-id>';

-- Delete user
DELETE FROM "authUsers" WHERE id = '<user-id>';

Security Updates

Stay updated:
# Update dependencies
pnpm update

# Check for vulnerabilities
pnpm audit

# Auto-fix vulnerabilities
pnpm audit fix
Subscribe to:

Reporting Vulnerabilities

Report security issues to: Do not open public issues for security vulnerabilities.

Next Steps

Production Deployment

Deploy securely to production

Configuration

Configure deployment and runtime options