Your coding agent can read your .env. Here's how I reduced the risk A developer documented a method for keeping secrets out of reach of coding agents by moving credential values from project .env files into 1Password and committing only op:// references in an op.env file, then launching apps via 'op run --env-file=op.env -- pnpm dev'. The approach limits casual discovery of secrets in readable files but, the developer cautions, does not protect against an agent that can run the op CLI, access the vault, or inspect a process that received the resolved values. If a coding agent can read your project files, assume it can read your .env too. Ignore rules and editor settings can help, but they are not a security boundary. I moved secret values out of my project files and into 1Password, then used the CLI to provide them to the processes that need them. That reduces one easy way for an agent to discover secrets. It does not make secrets safe from code the agent writes or commands it runs. I’ll cover that part too. Before, my project had a file containing actual values: .env STRIPE API KEY=replace-with-your-key SENTRY TOKEN=replace-with-your-token API URL=http://localhost:8787 Now, the shared secrets live in 1Password. The project contains references to them instead: op.env STRIPE API KEY=op://My-Project/api-env/STRIPE API KEY SENTRY TOKEN=op://My-Project/api-env/SENTRY TOKEN Then I start the app with: op run --env-file=op.env -- pnpm dev op run resolves the references and provides the values to the process it starts. It does not, by itself, write those resolved values to a file. An agent that reads op.env sees references, not secret values. But if it can run op , access the vault, or inspect a process that received the secrets, that protection may not be enough. Not every environment variable is a secret. Go through your existing files one value at a time: op.env . .env.local . For example: | File | Contents | Git | |---|---|---| | .env.local | Non-sensitive, machine-specific settings | Ignored | | op.env | References to shared secrets | Committed | Make sure .env.local is actually ignored. Add it to .gitignore if it isn’t already: .env.local The op:// references reveal metadata such as vault, item, and field names, so use names you’re comfortable exposing in the repository. Don’t point development references at a vault containing production credentials. The desktop app and CLI are separate installations. Follow 1Password’s CLI installation guide https://developer.1password.com/docs/cli/get-started/ for your platform. macOS brew install --cask 1password-cli Windows winget install AgileBits.1Password.CLI In the 1Password desktop app, enable Settings → Developer → Integrate with 1Password CLI . Then open a new terminal and try: op vault list Authenticate when prompted, and check that you can see the vault you intend to use. Keep the development vault scoped to development credentials. Do this yourself, in a terminal or the 1Password app—not through the coding agent. If the agent reads the old file while you migrate it, the secret has already entered the environment you’re trying to protect. Create an item in 1Password and add each secret as a concealed field. Avoid passing secret values as command-line arguments: depending on the system and tooling, arguments can be exposed through process listings or monitoring. Then create op.env with one reference per secret. For example: STRIPE API KEY=op://My-Project/api-env/STRIPE API KEY SENTRY TOKEN=op://My-Project/api-env/SENTRY TOKEN Keep the file format simple: one NAME=op://... reference per line. This check flags any non-comment, non-blank line that doesn’t match that format: grep -nEv '^ | A-Za-z A-Za-z0-9 =op://|$ ' op.env No output means every line matches the expected shape. It does not prove the references point to the right fields, or that a secret wasn’t committed elsewhere. Check the diff before committing, and rotate any credentials an agent may already have seen. Moving a credential into a vault does not undo an earlier exposure. op run For most apps, start the process that needs the secrets through 1Password: op run --env-file=op.env -- pnpm dev The secret values are now available to the app and its child processes. They are no longer just references—but they are still accessible to code running in that process. Give each service only the secrets it needs. If you run multiple services, use separate references or vault items rather than handing every service the same broad set of credentials. Wrangler’s local variable-file behavior matters here. If .dev.vars exists, Wrangler may not use the process environment the way you expect. Wrangler 4.27 and later support .env.local ; CLOUDFLARE INCLUDE PROCESS ENV=true enables merging the process environment as well. Check the Wrangler environment variable documentation https://developers.cloudflare.com/workers/wrangler/system-environment-variables/ for the behavior in the version you use. If you currently use .dev.vars : .dev.vars . Bash or zsh: if -f op.env ; then CLOUDFLARE INCLUDE PROCESS ENV=true \ op run --env-file=op.env -- wrangler dev else wrangler dev fi PowerShell: php if Test-Path op.env { $previous = $env:CLOUDFLARE INCLUDE PROCESS ENV try { $env:CLOUDFLARE INCLUDE PROCESS ENV = 'true' op run --env-file=op.env -- wrangler dev } finally { $env:CLOUDFLARE INCLUDE PROCESS ENV = $previous } } else { wrangler dev } The process-environment setting can expose more of the environment than you intended to the Worker. Set it only for the command that needs it, and test the behavior with your Wrangler version. Avoid using op inject to write resolved secrets into .dev.vars or another project file. That puts plaintext back on disk. For CI, use a 1Password service account with read-only access to the specific vault it needs. Store its token as a GitHub Actions secret on a protected environment, not as a broadly available repository secret. This example loads secrets as step outputs rather than exporting them into the whole job environment: jobs: deploy: runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - name: Load secrets from 1Password id: op uses: 1password/load-secrets-action@v5 with: export-env: false env: OP SERVICE ACCOUNT TOKEN: ${{ secrets.OP SERVICE ACCOUNT TOKEN }} CLOUDFLARE API TOKEN: op://My-Project/ci/CLOUDFLARE API TOKEN STRIPE API KEY: op://My-Project/api-env/STRIPE API KEY - name: Deploy Worker uses: cloudflare/wrangler-action@v4 env: STRIPE API KEY: ${{ steps.op.outputs.STRIPE API KEY }} with: apiToken: ${{ steps.op.outputs.CLOUDFLARE API TOKEN }} accountId: ${{ vars.CLOUDFLARE ACCOUNT ID }} workingDirectory: workers/api secrets: | STRIPE API KEY The secrets input names the variables Wrangler should upload; the values come from the step’s environment. Keep the service-account token and loaded values away from steps that do not need them. Before using this, check the actions’ current documentation. For stronger supply-chain protection, pin actions to reviewed commit SHAs rather than relying only on version tags. Never make secrets available to workflows running untrusted code, such as pull requests from forks. A vault keeps secret values out of files. It does not keep them out of processes. When op run starts your app, the app receives ordinary environment variables. Code in that process can read them. A malicious dependency or a change the agent made could send them over the network. Other processes running as your user may also be able to inspect process environments. For example, macOS has ps eww