Security
Secrets and configuration for AI-built apps
Keep keys out of code, out of images and out of prompts. Separate configuration by environment, rotate on schedule, and know what to do the day a key leaks.
Two kinds of setting
Every application has settings that change between environments. Split them in two:
- Configuration is anything you would be comfortable reading aloud: a log level, a feature flag, the public URL of the app, a region. It can live in plain environment variables.
- Secrets are anything that grants access: database passwords, API keys for payments or email, signing keys, OAuth client secrets, webhook tokens. They need to be stored, delivered and rotated with more care.
When in doubt, treat a value as a secret.
Why AI-built apps leak more often
Coding assistants are productive and literal. Ask for “a working Stripe integration” and you may get a key inlined in a module so the example runs. Paste an error message that contains a connection string and that string is now in a conversation history. Generate a quick docker-compose.yml and the password is in the file, and the file is in the repository.
None of that is malicious. It is just the shortest path to “it works”, and it is the path you need to undo before the app goes anywhere public.
Rule 1: never in code
Search your repository for anything that looks like a key: long random strings, sk_, -----BEGIN, password=, connection URLs with credentials. Move every one of them to an environment variable and read it at runtime.
Then add a secret scanner to your workflow so new ones are caught before they are committed. Many Git hosts can block pushes that contain known key formats; turn that on.
Rule 2: never in the image
Images are copied, cached and shared. Never COPY .env into an image and never pass secrets as build arguments. Both leave the value in a layer, where anyone with the image can read it. Deleting the file in a later layer does not remove it.
Secrets are injected when the container starts, by the platform, from a secret store.
Rule 3: never in the prompt
A conversation is not a vault. Do not paste keys into your assistant to “set them up”. When Kapten needs a secret value, the set_secret tool stores it without echoing it back into the conversation or into logs, and agents refer to secrets by name only.
If you have pasted a key into a chat, treat it as exposed and rotate it.
.env hygiene
Local .env files are fine, as long as they stay local:
- Add
.envand.env.*to.gitignoreand.dockerignorebefore you create them. - Commit a
.env.examplewith every variable name and a placeholder, so the next person (or agent) knows what the app expects. - Use separate, low-privilege credentials for local development. Your laptop should not hold production keys.
One set per environment
Each environment gets its own secrets:
- Development and previews: test-mode keys for payments, sandboxed email, a throwaway database.
- Staging: its own credentials, with access to staging data only.
- Production: credentials that exist nowhere else.
| Secret | Dev and previews | Staging | Production |
|---|---|---|---|
| Payment keys | Test mode | Test mode | Live, restricted |
| Email provider | Sandbox | Sandbox | Live, send-only |
| Database credentials | Throwaway | Staging data only | App user, least privilege |
| Wide access for agentsRead and change without approval | Yes | Yes | No |
| Exists on a laptopLow-privilege local copies only | Partial | No | No |
This is what makes it safe to give developers and agents wide access to non-production environments. A staging key that leaks cannot charge a real card or read a real customer’s data.
Least privilege for every key
Most providers let you create restricted keys. Use them:
- A key that only sends email does not need to manage domains.
- A database user for the application does not need to create or drop databases.
- A storage credential for uploads does not need to list every bucket.
When a scoped key leaks, the damage is the scope.
Rotation
Rotate secrets on a schedule and whenever someone with access leaves. Rotation goes smoothly when the application can accept two valid credentials during the switch:
- Create the new credential.
- Store it and roll the service so it uses the new value.
- Confirm health and traffic.
- Revoke the old credential.
- CreateNew credential at the provider.
- Gate: HealthStore and rollhelmsmanStored by name, service restarted.
- Gate: Both validConfirmlookoutTraffic and errors look normal.
- RevokewardenOld credential stops working.
If the app cannot run with the old and new credentials overlapping, rotation means downtime, and that means it will not happen. Fix that first.
The day a key leaks
It will happen. When it does, work in this order:
- Revoke or rotate the key immediately. Removing it from the repository is not enough: it is in the history, in forks and possibly in caches.
- Check the provider’s logs for use of the key since the leak.
- Remove it from history if the repository is public, and invalidate any caches. Do this after rotating, not instead.
- Find out how it got there and add the control that would have stopped it: a scanner, a pre-commit hook, a restricted key.
- Write it down. A short note of what happened and what changed is enough.
- 09:14Key pushed in a commit, FailedA payment key inlined by a generated example.
- 09:16Scanner flags the commitwardenFinding raised with severity high.
- 09:21Key rotated, LiveNew key stored and rolled; old key revoked.
- 09:35Provider logs checked, LiveNo use of the old key since the push.
- 10:05History rewritten, In progressAfter rotation, never instead of it.
- 10:30Pre-commit hook added, QueuedThe control that would have stopped it.
How Kapten handles secrets
- Secrets are stored per environment and injected at runtime. They are never written into images or logs.
- The Warden scans repositories, images and environment variables for secrets and reports each finding with a severity and a fix. It runs as part of the security posture audit and before first deployments.
set_secretcreates and rotates values without echoing them into the conversation.- Agents reference secrets by name, and their access follows the scope of the connection.
Secret storage and rotation capabilities are confirmed for your account during early access. See Security for the broader boundary, and the glossary for terms used here.
Build with Kapten
Start with one service.
Build from there.
Tell us what you want to deploy. We review each request and follow up about fit and onboarding on your preferred cloud.
Free during early access. No card required. Cloud usage billed separately.