Blog · 2026-05-28

Secrets your agent can use but never see

DenkOps env vars are encrypted, write-only after saving, and injected at run. Your AI agent deploys code that uses secrets it can never read back.

On DenkOps an environment variable is write-only. You save it once, it is stored encrypted, and after that nothing can read the value back through the platform: not the dashboard, not the CLI, and not the AI agent that built and deployed the app. The only place the value exists in plain text is inside your running process, injected at run.

Why does write-only matter more when an agent does the deploying?

Because the deployer is no longer only you. The whole point of shipping a backend from Claude Code is that the agent writes the code, deploys it, and iterates. That agent operates with your permissions, and everything it observes lands in its context: transcripts, logs, whatever tooling wraps it. If the platform could echo a secret back, any agent with deploy access could pull your CRM key into that context by accident, and from there it goes wherever the context goes.

Write-only closes the loop. The agent can create the variable, reference it by name, wire it into code, deploy, and debug, all without ever observing the value. You paste the value exactly once, and the interesting failure mode, "the agent leaked a secret it read from the platform", stops being possible because the read does not exist.

How does my code use a secret it cannot read back?

The same way it always has: process.env at run time. Here is an MCP tool handler an agent might write, calling a CRM with a key it knows only by name:

import { z } from "zod";
import { defineMcp } from "@denkopsai/sdk/mcp";

export default defineMcp({
  name: "crm-tools",
  version: "1.0.0",
  tools: {
    create_contact: {
      description: "Create a contact in the CRM by email address.",
      input: z.object({ email: z.string().email() }),
      handler: async ({ email }) => {
        const res = await fetch("https://api.example-crm.com/contacts", {
          method: "POST",
          headers: {
            authorization: `Bearer ${process.env.CRM_API_KEY}`,
            "content-type": "application/json",
          },
          body: JSON.stringify({ email }),
        });
        if (!res.ok) throw new Error(`CRM answered ${res.status}`);
        return res.json();
      },
    },
  },
});

Every line of that file can be written, reviewed, and redeployed by an agent. CRM_API_KEY appears only as a name. When the MCP server starts, the platform decrypts the value and injects it into the process environment, and the handler works.

What is the lifecycle of a secret on DenkOps?

Three moments. At save time, the value is encrypted and becomes write-only; the dashboard will confirm the variable exists but never show its content again. At run time, it is injected into your process's environment, and nowhere else. At rotation time, you overwrite the variable with a new value and the next run of the app picks it up; the old value was never readable, so there is nothing to clean out of histories or agent transcripts.

One guardrail pairs well with this. Even code that holds a secret in memory can only send it where you allow: outbound traffic from a DenkOps app is limited to an egress allowlist you control. A prompt-injected agent that rewrites your handler to POST the key elsewhere still hits a wall, because "elsewhere" is not on the list.

FAQ

Can I read an environment variable back after saving it on DenkOps?

No. Variables are write-only after saving. The dashboard and CLI show that a variable exists, but the value is encrypted and never returned. The only consumer of the plain-text value is your running process, which receives it at run.

How do I rotate a secret if I cannot read the old one?

Save a new value under the same name, exactly as you set it the first time. The next run of your app is injected with the new value. Rotation never requires reading the old secret, which is the point: values only ever flow in.

Can the AI agent that deploys my app see my secrets?

No. An agent can create and reference variables by name, deploy code that uses them, and read logs, but it can never retrieve a saved value. The secret is injected into the app process at run time, not into the agent's context.

Ship it yourself: bunx denkops deploy or say "deploy on DenkOps" from your coding agent.

Start on DenkOps →

← A webhook your agent can query · "connector: true" is a full OAuth stack in one flag →