Secure development checklist and decision framework

· Tech · AI-written from my notes

A quick-reference companion to the series on secure local development.

Decision framework: what goes where

1Password: human credentials only

Website logins, 2FA TOTP codes, SSH keys (via 1Password SSH agent), credit card numbers, secure notes, software license keys, Wi-Fi passwords, and identity documents.

Infisical: application and development secrets

Database connection strings, API keys (Stripe, SendGrid, Cloudflare, etc.), JWT secrets and session secrets, OAuth client secrets, encryption keys, service-to-service tokens, third-party SDK credentials, and any value that appears in your app’s environment.

Docker Compose: development runtime

Runs your application code with secrets injected by Infisical. The app containers see environment variables. The host filesystem never contains secret values. Hot-reload works via volume-mounted source code.

Docker sandbox: AI agent workspace

Contains only source code and the agent’s own API key. Zero access to runtime secrets. All AI-generated changes are tested in the separate Docker Compose stack where real secrets exist.

Summary matrix

Secret typeStorageAccess methodAI agent can see?
Website passwords1PasswordBrowser extensionNo
2FA codes1PasswordApp / autofillNo
SSH keys1Password SSH agentAgent forwardingNo
Database credentialsInfisicalinfisical run → Docker envNo
API keysInfisicalinfisical run → Docker envNo
JWT/session secretsInfisicalinfisical run → Docker envNo
EAS Build secretsInfisicalinfisical run → eas buildNo
Public env varsdocker-compose.ymlHardcoded in compose fileYes (safe)
EXPOPUBLIC* varsHost shell / app.config.tsExpo CLI on hostYes (safe, public by design)
Source codeGitVolume mountYes (intended)
.env.exampleGitCommitted with placeholdersYes (safe)
API responsesDev API containerhost.docker.internal:3333Yes (intended, no secrets in responses)
Terraform secretsInfisicalTerraform provider + ephemeral resourcesNo (never in state files)

Security hardening checklist

Files that must never exist on disk

  • No .env files anywhere in project directories
  • No .env.local, .env.development, .env.production files
  • No config.json or secrets.yaml with real credentials
  • No credentials.json (GCP service accounts, etc.)
  • No private keys outside of 1Password or macOS Keychain
  • No inline secrets in MCP config files (claude_desktop_config.json, .mcp.json)
  • No encrypted offline cache files left on disk after returning online
  • .cache/infisical/ and *.age added to .gitignore and .claudeignore

Git safety

  • .env* in .gitignore (except .env.example)
  • Pre-commit hook with infisical scan installed and working
  • Git history scanned for leaked secrets (infisical scan)
  • No secrets in CLAUDE.md or README.md
  • No secrets in Dockerfile ARGs or ENV instructions
  • Review AI-generated commits for accidentally embedded credentials
  • Shared hooks directory (.githooks/) committed to repo for team-wide enforcement

AI agent isolation

  • AI agents run in Docker Sandboxes or isolated containers
  • No Docker socket mounted into AI containers
  • .claudeignore includes .env*, *.pem, *.key, *.age, MCP configs, credentials patterns
  • CLAUDE.md instructs agent to never read/write env files
  • CLAUDE.md documents how to reach dev services via host.docker.internal
  • AI sandbox has no access to host environment variables
  • AI and dev server run in separate terminal sessions
  • AI agent network access limited to necessary services only (API yes, DB no)
  • Claude’s built-in permission system NOT relied upon; nono or Docker isolation is the security boundary
  • No time spent configuring trust levels, allowed tools, or approval lists in Claude settings
  • --dangerously-skip-permissions used inside sandbox (safe because container enforces isolation)
  • MCP servers with sensitive credentials run outside the AI sandbox, not inside it
  • Third-party AI agent extensions and skills treated as untrusted (contained by sandbox)
  • npm/pip installs inside sandbox cannot exfiltrate secrets (nothing to steal)

Expo / React Native

  • Only EXPO_PUBLIC_* variables used in Expo app code
  • No secrets in app.config.ts during local development
  • Build-time secrets injected via infisical run -- eas build
  • eas.json does not contain secrets (only build profiles)
  • .claudeignore includes ios/, android/, .expo/, provisioning profiles, keystores
  • GoogleService-Info.plist and google-services.json added to .claudeignore
  • Expo dev server runs on host, not in Docker

Infisical configuration

  • Separate projects for each application
  • Separate environments (dev/staging/production) with different values
  • Production credentials in a separate project with restricted access
  • Audit log reviewed periodically
  • Session logged out when not actively developing
  • Machine identities used for CI/CD (not personal tokens)
  • Terraform/OpenTofu uses Infisical provider with machine identity (not personal token)
  • Ephemeral resources used in Terraform v1.10+ to keep secrets out of state files
  • OIDC authentication used for CI/CD pipelines (no static tokens in GitHub Actions)

macOS system security and host tools

  • macOS and all apps kept up to date
  • FileVault enabled (full-disk encryption)
  • Firewall enabled
  • No unnecessary accessibility permissions granted
  • Lockdown Mode considered for high-sensitivity work
  • Avoid installing npm packages globally with sudo
  • Review Homebrew formulas before installing (brew cat <package>)
  • Use official Homebrew taps only, avoid third-party taps for critical tools
  • Pin versions of daily-use tools (brew pin helix lazygit)
  • Update pinned tools deliberately and review changelogs
  • Use nono to sandbox CLI tools on macOS (nono run --allow ~/project --net-block -- hx .)
  • Consider building critical tools from source (Helix: cargo build, lazygit: go build)
  • Consider Nix for reproducible, source-based package management
  • Log out of Infisical (infisical logout) when not actively developing
  • Consider running editing tools inside Dev Containers for high-security projects
  • Consider a separate machine for projects handling private keys or real money

Docker security

  • Docker Desktop kept up to date
  • No --privileged flag on development containers
  • No Docker socket mounted into any container unless absolutely necessary
  • Container images pinned to specific versions (not :latest in production)
  • Containers run as non-root users where possible

Incident preparedness

  • Secret rotation procedure documented and tested
  • Infisical audit log accessible and reviewed
  • infisical scan run periodically on all repos
  • Team knows the “rotate first, investigate second” protocol
  • Contact info for API providers (Stripe, AWS, etc.) readily available for emergency revocations

Team (when applicable)

  • AI sandbox policy documented in CONTRIBUTING.md
  • Shared git hooks directory (.githooks/) in repo
  • RBAC configured: juniors = dev only, seniors = dev + staging, DevOps = all
  • Machine identities per CI/CD pipeline, scoped to one project and environment
  • Offboarding runbook includes secret rotation for all accessed environments
  • .env.example validation script runs in CI
uptime
8,215 days · since 2004
posts
294 · busiest 2026 (64)
words
~143,065 · ~10 h read
topics
tech 239 · personal 55
langs
en 229 · pl 65
written
211 by hand · 83 AI-assisted
projects
3
build
ca50768 · 2026-06-30