What is runtime secret injection?
On this page
Runtime secret injection is the practice of delivering secrets to a program at the moment it starts, usually as environment variables set by a wrapper, an agent or the platform, so that the values never sit in the source code, the built image or a file in the project directory.
Build time versus run time
There are three common moments to give a program its secrets:
| When | Example | Where the value ends up |
|---|---|---|
| In the code | const key = "sk_live_…" | the repository and every copy of it |
| At build time | Docker ARG, a front-end build variable | the image or bundle, for anyone who can pull it |
| At run time | a wrapper starts the process with the variables | the running process's memory and environment |
Run time is the only one where the value isn't copied into an artifact. The OWASP cheat sheet calls build-time injection "not recommended" and says secrets "should never be hardcoded using docker ENV or docker ARG commands" (OWASP).
Ways to do it
- A run wrapper. A command that fetches the values and starts your program with them, like
crunu run -- npm start. - The platform. Container orchestrators, PaaS dashboards and CI systems set variables when they start a process.
- A file written at start and read once, for programs that only take config files. This is weaker, because the file exists for a while.
Why it matters for AI agents
A coding agent reads files in your project and runs commands. If the project has a .env with real values, the agent can read it, quote it in a reply or send it in a request. With injection at run time, the project directory holds no values: only the program you start receives them. That removes the most common path by which agents see secrets.
It doesn't remove all of them. The program, and anything it starts, can read its own environment. If an agent can run the wrapper itself, it can start any program with the values, including one that prints them.
Common mistakes
- Inheriting everything. A wrapper that passes the full parent environment also hands over unrelated credentials from your shell.
- Logging the environment on startup for debugging.
- Writing the values to disk "just for now". That is a
.envfile again. - Exporting into your interactive shell. See sourcing an env file: every later command gets the values.
Runtime injection with Crunu
crunu run decrypts an environment in memory and starts your program with its variables. Nothing is written to disk.
crunu run --env web-app/development -- npm run devBy default the program receives a short allowlist from the parent environment, such as PATH, HOME and LANG, plus the environment's variables, and never crunu's own credentials such as CRUNU_TOKEN. On Linux, the crunu process also closes itself to other processes of the same user, though not to root. With --restart on-change, a new version of the environment restarts the program with the new values.
The same command runs on servers under systemd and in CI with a service token. Crunu has no agent-specific controls: the separation comes from where values live, not from detecting agents. While an agent works unattended, lock your session with crunu lock. More on this setup: keep secrets away from AI coding agents.
Sources
- OWASP Secrets Management Cheat Sheet, checked October 30, 2026.
From the blog
AI agents
Do AI coding agents read your .env files?
What Claude Code, Cursor and Copilot do with .env files by default, why ignore rules don't stop an agent's shell, and how to test it with a fake key.
AI coding agents guide
Servers
Secrets in Docker images: build args, layers and checks
ARG and ENV values stay in a Docker image, and deleting a file in a later layer doesn't remove it. How to build with secret mounts and check an image.
Sharing .env files guide
Servers
One .env file, four parsers: Node, Python, Docker, systemd
The same .env line can give three different values. We ran one file through Node, dotenv, python-dotenv, Compose and docker run, and read systemd's rules.
Sharing .env files guide