> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/paperclipai/paperclip/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Secure your Paperclip deployment with authentication, secrets management, and best practices

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:**

```bash theme={null}
PAPERCLIP_DEPLOYMENT_MODE=authenticated
PAPERCLIP_DEPLOYMENT_EXPOSURE=public
PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com
```

## Authentication

### Board Authentication

Paperclip uses [Better Auth](https://better-auth.com) 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:

```bash theme={null}
pnpm paperclipai agent create-key <agent-id>
```

**Use API key:**

```bash theme={null}
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:**

```typescript theme={null}
{
  sub: agent.id,
  company_id: agent.companyId,
  run_id: currentRunId
}
```

See `server/src/agent-auth-jwt.js`.

### Authorization

All API endpoints enforce:

**Company access:**

```typescript theme={null}
// 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:**

```typescript theme={null}
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`**

```bash theme={null}
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:

```bash theme={null}
mkdir -p ~/.paperclip/instances/default/secrets
openssl rand -hex 32 > ~/.paperclip/instances/default/secrets/master.key
```

### Strict Mode

**Prevent inline secrets in environment variables:**

```bash theme={null}
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:

```json theme={null}
// ❌ 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:**

```bash theme={null}
# 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:**

<AccordionGroup>
  <Accordion title="Use short-lived keys for testing">
    Create temporary keys, revoke after testing.
  </Accordion>

  <Accordion title="Rotate keys regularly">
    Create new key, update agent config, revoke old key.
  </Accordion>

  <Accordion title="Use separate keys per agent">
    Don't share keys across agents - isolate blast radius.
  </Accordion>

  <Accordion title="Store keys in secret manager">
    Use 1Password, AWS Secrets Manager, etc.
  </Accordion>

  <Accordion title="Monitor key usage">
    Check `lastUsedAt` for anomalies.
  </Accordion>
</AccordionGroup>

### Key Format

```
paperclip_agent_<random>
```

Example:

```
paperclip_agent_1a2b3c4d5e6f7g8h9i0j...
```

### Revoke a Key

**Via UI:** Agent > Settings > Revoke Key

**Via database:**

```sql theme={null}
UPDATE agent_api_keys 
SET revoked_at = NOW() 
WHERE id = '<key-id>';
```

## Network Security

### HTTPS

**Always use HTTPS in production:**

```bash theme={null}
# Behind reverse proxy (nginx, Caddy, Cloudflare)
PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com
```

**Reverse proxy example (Caddy):**

```caddy theme={null}
paperclip.example.com {
  reverse_proxy localhost:3100
}
```

Caddy auto-manages TLS certificates.

### Firewall Rules

**Restrict database access:**

Only allow connections from application servers:

```bash theme={null}
# 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:

```sql theme={null}
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`:

```typescript theme={null}
{
  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:**

```typescript theme={null}
// ❌ 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

<Steps>
  <Step title="Use authenticated mode">
    ```bash theme={null}
    PAPERCLIP_DEPLOYMENT_MODE=authenticated
    PAPERCLIP_DEPLOYMENT_EXPOSURE=public
    ```
  </Step>

  <Step title="Enable strict secrets mode">
    ```bash theme={null}
    PAPERCLIP_SECRETS_STRICT_MODE=true
    ```
  </Step>

  <Step title="Disable company deletion">
    ```bash theme={null}
    PAPERCLIP_ENABLE_COMPANY_DELETION=false
    ```
  </Step>

  <Step title="Use hosted PostgreSQL">
    Don't use embedded PostgreSQL in production.
  </Step>

  <Step title="Use S3 for storage">
    ```bash theme={null}
    PAPERCLIP_STORAGE_PROVIDER=s3
    ```
  </Step>

  <Step title="Set explicit public URL">
    ```bash theme={null}
    PAPERCLIP_AUTH_PUBLIC_BASE_URL=https://paperclip.example.com
    ```
  </Step>

  <Step title="Use HTTPS">
    Deploy behind reverse proxy with TLS.
  </Step>

  <Step title="Restrict database access">
    Use firewall rules and VPC.
  </Step>

  <Step title="Rotate secrets master key">
    Store in secret manager, not in environment.
  </Step>

  <Step title="Monitor health endpoint">
    ```bash theme={null}
    curl https://paperclip.example.com/api/health
    ```
  </Step>
</Steps>

### Security Validation

Run the doctor command:

```bash theme={null}
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**
   ```sql theme={null}
   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:

```sql theme={null}
-- 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:**

```bash theme={null}
# Via CLI (if user is not instance admin)
pnpm paperclipai user delete <user-id>
```

**Manual cleanup:**

```sql theme={null}
-- 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:

```bash theme={null}
# Update dependencies
pnpm update

# Check for vulnerabilities
pnpm audit

# Auto-fix vulnerabilities
pnpm audit fix
```

Subscribe to:

* [GitHub Security Advisories](https://github.com/paperclipai/paperclip/security/advisories)
* [Dependabot alerts](https://github.com/paperclipai/paperclip/security/dependabot)

## Reporting Vulnerabilities

Report security issues to:

* **Email:** [security@paperclip.ing](mailto:security@paperclip.ing)
* **GitHub:** Private security advisory

**Do not** open public issues for security vulnerabilities.

## Next Steps

<CardGroup cols={2}>
  <Card title="Production Deployment" icon="server" href="/deployment/production">
    Deploy securely to production
  </Card>

  <Card title="Configuration" icon="gear" href="/deployment/configuration">
    Configure deployment and runtime options
  </Card>
</CardGroup>
