Skip to content

Generate valid secrets in the CLI bootstrap#3619

Open
dipeshbabu wants to merge 1 commit intosimstudioai:mainfrom
dipeshbabu:fix/cli-generate-valid-secrets
Open

Generate valid secrets in the CLI bootstrap#3619
dipeshbabu wants to merge 1 commit intosimstudioai:mainfrom
dipeshbabu:fix/cli-generate-valid-secrets

Conversation

@dipeshbabu
Copy link

Summary

Generate valid runtime secrets for the simstudio Docker bootstrap instead of passing placeholder values.

Problem

The CLI currently starts the app with placeholder secrets:

  • BETTER_AUTH_SECRET=your_auth_secret_here
  • ENCRYPTION_KEY=your_encryption_key_here

This can break the one-command startup flow because the app expects real secrets, and the encryption layer requires a 64-character hex key.

Changes

  • generate BETTER_AUTH_SECRET at runtime
  • generate ENCRYPTION_KEY as a 32-byte hex string
  • generate INTERNAL_API_SECRET and API_ENCRYPTION_KEY for parity with local compose defaults
  • pass generated secrets into the app and realtime containers

Validation

  • cd packages/cli && bun run type-check
  • run npx simstudio on a clean Docker setup and confirm the app boots successfully

@vercel
Copy link

vercel bot commented Mar 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 17, 2026 4:13am

Request Review

@cursor
Copy link

cursor bot commented Mar 17, 2026

PR Summary

Low Risk
Low risk: the change is limited to the CLI Docker bootstrap and only replaces placeholder environment variables with generated secrets, affecting local startup configuration but not core application logic.

Overview
The simstudio CLI now generates valid runtime secrets (hex via crypto.randomBytes) instead of passing placeholder values when bootstrapping Docker.

These generated values are injected into the simstudio app and realtime containers for BETTER_AUTH_SECRET, ENCRYPTION_KEY, and the newly provided INTERNAL_API_SECRET and API_ENCRYPTION_KEY, improving one-command startup reliability.

Written by Cursor Bugbot for commit 96370cc. This will update automatically on new commits. Configure here.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 17, 2026

Greptile Summary

This PR replaces hardcoded placeholder secrets (your_auth_secret_here, your_encryption_key_here) in the CLI bootstrap with cryptographically secure, randomly-generated hex values using Node's built-in crypto.randomBytes. It also adds INTERNAL_API_SECRET and API_ENCRYPTION_KEY to both containers for parity with local compose defaults.

Key issues found:

  • Critical – data loss on restart: All four secrets are regenerated fresh on every run of npx simstudio. The PostgreSQL data volume (~/.simstudio/data/postgres) persists across restarts, but the ENCRYPTION_KEY and API_ENCRYPTION_KEY change each time, making any previously-encrypted rows in the database permanently unreadable. BETTER_AUTH_SECRET changing also invalidates all existing user sessions. Secrets must be persisted to a local config file (e.g., ~/.simstudio/secrets.json) on first run and reloaded on subsequent runs.

  • Positive: The generateHexSecret helper correctly uses randomBytes from Node's crypto module, which is cryptographically secure. randomBytes(32).toString('hex') produces a 64-character hex string, satisfying the documented requirement for ENCRYPTION_KEY.

Confidence Score: 2/5

  • Not safe to merge as-is — restarting the CLI will corrupt encrypted data in the persisted database volume due to regenerated encryption keys.
  • The core intent (replacing placeholder secrets with real random values) is correct and the cryptographic primitives used are sound. However, the implementation has a critical flaw: secrets are regenerated on every invocation while the PostgreSQL data volume persists, meaning encrypted data written in one session becomes unreadable after any restart. This is a data-loss bug that must be fixed before merging.
  • packages/cli/src/index.ts — secret persistence logic needs to be added before this is safe to ship

Important Files Changed

Filename Overview
packages/cli/src/index.ts Adds cryptographically secure secret generation for Docker bootstrap, replacing placeholder strings. However, secrets are regenerated on every run, which will corrupt encrypted data in the persisted PostgreSQL volume and invalidate all auth sessions on each restart — a critical data-loss issue.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as CLI (index.ts)
    participant Docker
    participant DB as PostgreSQL Container
    participant RT as Realtime Container
    participant App as App Container

    User->>CLI: npx simstudio
    CLI->>CLI: generateHexSecret() x4<br/>(betterAuthSecret, encryptionKey,<br/>internalApiSecret, apiEncryptionKey)
    CLI->>Docker: cleanupExistingContainers()
    Docker-->>CLI: old containers removed
    CLI->>Docker: run pgvector/pgvector:pg17
    Docker-->>DB: start (volume: ~/.simstudio/data/postgres)
    CLI->>Docker: run migrations container
    Docker-->>CLI: migrations complete
    CLI->>Docker: run realtime container<br/>-e BETTER_AUTH_SECRET<br/>-e INTERNAL_API_SECRET
    Docker-->>RT: start
    CLI->>Docker: run app container<br/>-e BETTER_AUTH_SECRET<br/>-e ENCRYPTION_KEY<br/>-e INTERNAL_API_SECRET<br/>-e API_ENCRYPTION_KEY
    Docker-->>App: start

    Note over CLI,App: ⚠️ On restart: new secrets are<br/>generated, but DB volume persists.<br/>Old encrypted data becomes unreadable.
Loading

Last reviewed commit: 96370cc

Comment on lines +92 to +95
const betterAuthSecret = generateHexSecret()
const encryptionKey = generateHexSecret()
const internalApiSecret = generateHexSecret()
const apiEncryptionKey = generateHexSecret()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Secrets regenerated on every restart — encrypted data becomes unreadable

New secrets are generated on every invocation of npx simstudio. Because cleanupExistingContainers() stops and removes the old containers but the PostgreSQL data volume at ~/.simstudio/data/postgres is persisted on disk, the next startup uses a different ENCRYPTION_KEY and API_ENCRYPTION_KEY against a database that already has data encrypted under the previous keys. This will silently make any previously-encrypted credential/secret rows unreadable.

Similarly, BETTER_AUTH_SECRET changing on every restart will invalidate all existing user sessions, forcing re-authentication every time the CLI is re-run.

The fix is to persist the generated secrets to disk the first time they are created and reload them on subsequent runs. A simple approach:

// Persist/load secrets from ~/.simstudio/secrets.json
// On first run: generate all four values and write the file with mode 0o600
// On subsequent runs: read the file and reuse the same values

Key requirements:

  • The secrets file should only be created once (no regeneration if the file already exists)
  • The file permissions should be restricted to owner-only (0o600) to avoid leaking secrets to other users on the same machine
  • The ~/.simstudio/ directory already exists at this point in the flow (the dataDir mkdir runs earlier), so writing there is safe

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

const betterAuthSecret = generateHexSecret()
const encryptionKey = generateHexSecret()
const internalApiSecret = generateHexSecret()
const apiEncryptionKey = generateHexSecret()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Secrets regenerated on restart, corrupting persisted encrypted data

High Severity

ENCRYPTION_KEY, API_ENCRYPTION_KEY, BETTER_AUTH_SECRET, and INTERNAL_API_SECRET are freshly generated on every CLI invocation, but the PostgreSQL database is persisted across runs via a host volume at ~/.simstudio/data. On a second boot, the new random secrets won't match the ones used to encrypt existing data, making all previously encrypted values (credentials, API keys, auth sessions) unreadable. The secrets need to be persisted to disk (e.g., alongside the data directory) and reused on subsequent runs.

Additional Locations (1)
Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant