Learning paths / Vibe coding to production / Security of AI-written code

Secrets don't belong in code

Reading · 6 min · Module 6, lesson 1 of 423 min left in this module

Module 6 · Security of AI-written codeLesson 1 of 4

Goal: Move the starter's hard-coded key into an environment variable that fails closed, and store it as a ComputeSphere secret.

Key idea

A secret written into code is in your Git history, in every clone and fork, and in the context of every agent that opens the file. Read it from an environment variable, make the app refuse when it's missing, and on ComputeSphere store it as a secret.

Find it in the starter

Near the top of server.js:

const ADMIN_KEY = "demo-not-a-real-key-0000";

It guards GET /api/admin/stats: send the key in an x-admin-key header and you get task counts. Agents write keys like this because it makes the feature work on the first run. The value here is fake; in your own app it would be a real key to a real service.

Deleting the line in a later commit doesn't help. The old commit still has it, and so does every copy of the repository. A secret that reached Git is a leaked secret: replace it, then remove it from the code.

Fix it, and don't open the door

The obvious fix is one line: const ADMIN_KEY = process.env.ADMIN_KEY;. On its own, it makes things worse. If the variable isn't set, ADMIN_KEY is undefined; a request with no header also sends undefined, the two match, and anyone gets the stats.

Change both places:

const ADMIN_KEY = process.env.ADMIN_KEY;
app.get("/api/admin/stats", (req, res) => {
  if (!ADMIN_KEY || req.get("x-admin-key") !== ADMIN_KEY) {
    return res.status(401).json({ error: "unauthorized" });
  }

Now a missing key locks everyone out instead of letting everyone in. That's failing closed. Ask an agent to "move the key to an environment variable" and check its diff for exactly this line.

Try it locally

Make a new value with openssl rand -hex 24, and set it as ADMIN_KEY=<value> in your .env file, which Git ignores (lesson 4.2.2). Replace any ADMIN_KEY line already there. Then start the app with the file loaded:

node --env-file=.env server.js

In another terminal, curl -i localhost:3000/api/admin/stats answers 401. With the header, -H "x-admin-key: <your value>", it answers 200 and the counts. Run npm test, then commit.

Add the name to .env.example with an obviously fake value, so the next person, or agent, knows it's needed.

Keeping secrets away from your agent

An agent can open any file in the project, .env included, and whatever it reads goes to the model provider with the rest of its context. For keys that matter, use development keys locally, never production ones, and tell the agent in its instruction file (module 7) not to read or print .env.

Turn on secret scanning where your code lives. GitHub's push protection blocks many known key formats before they reach the repository. ComputeSphere tokens start with csph_ so scanners can spot them too.

Check yourself

An agent hard-coded a real API key last week. Today you removed the line and pushed. What's left to do?
Why does the fixed check start with !ADMIN_KEY?