Claude Fable 5.1 & GPT-6 Astra packages are live

Secret Management

Free · MIT

Keeping credentials out of source, configuration and images — storage, injection, rotation, and what to do once a secret has leaked.

203 lines8.0 KB Mistral Security
Target models
Mistral Medium 3.5Mistral Large 3Mistral Small 4Mistral FamilyFuture Mistral Models
Name
secret-management
Category
Security
Description
Keeping credentials out of source, configuration and images — storage, injection, rotation, and what to do once a secret has leaked.
License
MIT
Author
Agent.md maintainers
Last verified
2026-08-23
Reviewed by
unreviewed

#How to apply this file

Each section opens with one imperative line; apply every rule in the section it introduces. Do not summarise or skip a section.


#Purpose

Rules for handling API keys, database passwords, signing keys and tokens.

The operating assumption: a secret in source control is already compromised. Git history is permanent, forks are uncontrolled, and scanners crawl public repositories continuously. Treat "we will remove it later" as "we have rotated it" — because removing it without rotating changes nothing.


#Where secrets live

[INST] Apply every rule in this section: Where secrets live. [/INST]

LocationVerdict
Secret manager (Vault, AWS Secrets Manager, GCP Secret Manager, 1Password)Preferred — audited, rotatable, access-controlled
KMS / HSM for signing and encryption keysPreferred — the key never leaves the boundary
Platform-injected environment variablesAcceptable — the common baseline
CI/CD provider secret storeAcceptable for build-time credentials
.env file, gitignored, local development onlyTolerable — never in an image or a deployed host
Committed .env, config file, or source constantNever
Client bundle, mobile app, browser storageNever — shipped to every user

Never commit a secret "temporarily". Never paste one into an issue, a pull request, a chat message, or a support ticket — those systems are searchable and often exportable.


#Environment variables — the caveats

[INST] Apply every rule in this section: Environment variables — the caveats. [/INST]

Environment variables are the common baseline, and they leak in specific ways worth knowing:

  • They appear in crash dumps and error reporters. Scrub process.env before sending a report to Sentry or similar.
  • They are readable by every process the user runs, and on Linux via /proc/<pid>/environ for the same user.
  • docker inspect shows them for a running container.
  • They land in shell history when set inline on a command.
  • Child processes inherit them. A build step that shells out passes every secret along.
js
// Fail fast and loudly at startup rather than sending `undefined` as a key.
const required = ["DATABASE_URL", "JWT_SIGNING_KEY", "STRIPE_SECRET_KEY"];
const missing = required.filter((k) => !process.env[k]);
if (missing.length) {
  throw new Error(`Missing required secrets: ${missing.join(", ")}`);
}

Never log process.env, and never interpolate a secret into a log line, a URL, or an error message.


#Keeping them out of the repository

[INST] Apply every rule in this section: Keeping them out of the repository. [/INST]

gitignore
.env
.env.*
!.env.example
*.pem
*.key
*.p12
credentials.json
service-account*.json

Commit a .env.example with keys and empty values only — never real values — so a contributor knows what is required.

Run a secret scanner in CI and as a pre-commit hook (gitleaks, trufflehog, detect-secrets, or GitHub push protection). Scan the full history, not just the diff, when onboarding an existing repository.

Never rely on .gitignore alone. It does not protect a file already tracked, and git add -f bypasses it.


#Containers and builds

[INST] Apply every rule in this section: Containers and builds. [/INST]

  • Never use ENV SECRET=… or ARG SECRET=… in a Dockerfile. Both persist in the image layers and are readable with docker history by anyone who can pull the image.
  • Use build secrets that are not committed to a layer:
dockerfile
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npm_token \
    NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
  • Inject runtime secrets through the orchestrator — Kubernetes Secret mounted as a file, ECS task secrets, systemd credentials.
  • A Kubernetes Secret is base64, not encrypted, at rest by default. Enable encryption at rest, restrict RBAC on the secrets resource, and prefer an external-secrets operator backed by a real manager.

#Rotation

[INST] Apply every rule in this section: Rotation. [/INST]

  • Rotate on a schedule and immediately on any suspicion of exposure.
  • Design every integration to support two valid credentials at once, so rotation is: issue new → deploy → verify → revoke old. Without overlap, rotation means downtime, and rotation that means downtime does not happen.
  • Prefer short-lived, automatically issued credentials over long-lived static ones: IAM roles, workload identity, OIDC federation from CI. The best secret is the one that expires in an hour without anyone acting.
  • Keep an inventory: what exists, who can read it, when it was last rotated. An unrotatable secret nobody owns is the one that ends up in an incident report.

#When a secret leaks

[INST] Apply every rule in this section: When a secret leaks. [/INST]

In this order:

  1. Revoke or rotate first. Not "remove the commit" — revoke. The old value is already cloned, cached and indexed.
  2. Check for use. Review provider audit logs from before the leak was noticed.
  3. Then clean history if you wish (git filter-repo, BFG) and force-push. This is cosmetic; it does not un-leak anything and does not reach existing clones or forks.
  4. Record it. What leaked, how, for how long, and what changed to prevent a repeat.

Never treat a history rewrite as remediation. Rotation is remediation.


#Anti-patterns

[INST] Apply every rule in this section: Anti-patterns. [/INST]

Anti-patternWhy it failsFix
API key committed "temporarily"History is permanent; scanners are fastRotate; use a secret manager
ENV SECRET= in a DockerfileReadable via docker history--mount=type=secret
Secret in a client bundle or mobile appShipped to every userProxy through your backend
console.log(process.env)Secrets land in log aggregationNever log the environment
Same key across dev, staging and prodOne compromise takes everythingSeparate credentials per environment
No rotation because it causes downtimeRotation never happensSupport two valid credentials
Deleting the commit instead of rotatingClones and forks retain itRevoke first
Kubernetes Secret assumed encryptedBase64 is encodingEncryption at rest + RBAC
Secret in a URL query stringAccess logs, Referer, historyHeader or request body

#Checklist

  • Verify: No secret appears in source, config, or committed .env files
  • Verify: .gitignore covers .env*, *.pem, *.key, service-account JSON
  • Verify: .env.example lists keys with empty values only
  • Verify: A secret scanner runs in CI and over full history
  • Verify: Production secrets come from a secret manager or orchestrator injection
  • Verify: Required secrets are validated at startup with a clear failure
  • Verify: process.env is never logged and is scrubbed from error reports
  • Verify: No ENV/ARG secrets in Dockerfiles; build secrets use --mount=type=secret
  • Verify: Kubernetes secrets have encryption at rest and restricted RBAC
  • Verify: Each environment has distinct credentials
  • Verify: Every integration supports two valid credentials for zero-downtime rotation
  • Verify: Short-lived federated credentials used where the platform supports them
  • Verify: A written leak procedure exists that starts with revocation