Skip to content

Plain Text

Store secrets as plain text (for default values only!).

Usage

Plain text is the default when no provider is specified:

toml
[secrets.NODE_ENV]
default = "development"  # ← Plain text, safe for non-sensitive defaults

[secrets.LOG_LEVEL]
default = "info"  # ← Plain text

[secrets.API_TIMEOUT]
default = "30"  # ← Plain text

When Plain Text is Appropriate

1. Non-Sensitive Defaults

toml
[secrets.PORT]
default = "3000"

[secrets.HOST]
default = "localhost"

[secrets.NODE_ENV]
default = "development"

[secrets.LOG_LEVEL]
default = "info"

2. Public Configuration

toml
[secrets.PUBLIC_API_URL]
default = "https://api.example.com"

[secrets.CDN_URL]
default = "https://cdn.example.com"

3. Development Fallbacks

toml
[secrets.DATABASE_URL]
provider = "age"
value = "encrypted-production-db..."
default = "postgresql://localhost/dev_db"  # ← Fallback for local dev

If the encrypted value can't be decrypted (e.g., missing key), falls back to the plaintext default.

❌ When NOT to Use Plain Text

Never for Passwords

toml
# ❌ BAD - Never do this!
[secrets.DATABASE_PASSWORD]
default = "super-secret-password"

# ✅ GOOD - Use encryption
[secrets.DATABASE_PASSWORD]
provider = "age"
value = "encrypted..."

Never for API Keys

toml
# ❌ BAD
[secrets.STRIPE_KEY]
default = "sk_live_abc123xyz789"

# ✅ GOOD
[secrets.STRIPE_KEY]
provider = "age"
value = "encrypted..."

Never for Tokens

toml
# ❌ BAD
[secrets.JWT_SECRET]
default = "my-secret-key"

# ✅ GOOD
[secrets.JWT_SECRET]
provider = "age"
value = "encrypted..."

Mixing Plain and Encrypted

It's common to mix plain text defaults with encrypted values:

toml
# Encrypted sensitive values
[providers.age]
type = "age"
recipients = ["age1..."]

[secrets.DATABASE_PASSWORD]
provider = "age"
value = "encrypted..."
default = "dev-password"  # ← Fallback for local dev (non-production)

# Plain text non-sensitive defaults
[secrets.DATABASE_HOST]
default = "localhost"

[secrets.DATABASE_PORT]
default = "5432"

[secrets.LOG_LEVEL]
default = "info"

Security Best Practices

  1. Never commit sensitive data as plain text
  2. Use encryption for anything that shouldn't be public
  3. Use plain text only for truly non-sensitive defaults
  4. Review .gitignore - Ensure sensitive files aren't tracked
  5. Use fnox scan to detect secrets - Scans for accidentally committed secrets

Scan for Secrets

fnox can scan your codebase for accidentally committed secrets:

bash
# Scan for potential secrets
fnox scan

# Scan specific directory
fnox scan src/

# Scan and fix (interactive)
fnox scan --fix

Examples

Safe Plain Text Usage

toml
# Application settings (non-sensitive)
[secrets.APP_NAME]
default = "My Application"

[secrets.APP_VERSION]
default = "1.0.0"

[secrets.ENVIRONMENT]
default = "development"

[secrets.DEBUG_MODE]
default = "true"

[secrets.TIMEOUT_MS]
default = "5000"

# Public URLs
[secrets.PUBLIC_SITE_URL]
default = "https://example.com"

[secrets.DOCS_URL]
default = "https://docs.example.com"

Mixed Usage (Plain + Encrypted)

toml
[providers.age]
type = "age"
recipients = ["age1..."]

# Sensitive (encrypted)
[secrets.DATABASE_URL]
provider = "age"
value = "encrypted-connection-string..."

[secrets.API_KEY]
provider = "age"
value = "encrypted-key..."

# Non-sensitive (plain)
[secrets.DATABASE_POOL_SIZE]
default = "10"

[secrets.CACHE_TTL_SECONDS]
default = "3600"

[secrets.FEATURE_FLAG_NEW_UI]
default = "false"

Remember

  • ✅ Plain text is fine for public, non-sensitive configuration
  • ✅ Use defaults for fallback values
  • ❌ Never use plain text for passwords, keys, or tokens
  • ✅ Use age or other providers for sensitive data
  • ✅ Run fnox scan to catch accidental secrets

Next Steps

Released under the MIT License.