← back to Designer Wallcoverings
Draft gated Gemini key rotation memo (leaked AIza key in 6 Mac2 files + Kamatera cron)
2711b778faf57b28a7fd7d877edf5c684b18d21d · 2026-06-23 08:36:19 -0700 · Steve Abrams
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
A pending-approval/gemini-key-rotation.md
Diff
commit 2711b778faf57b28a7fd7d877edf5c684b18d21d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 23 08:36:19 2026 -0700
Draft gated Gemini key rotation memo (leaked AIza key in 6 Mac2 files + Kamatera cron)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
pending-approval/gemini-key-rotation.md | 80 +++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/pending-approval/gemini-key-rotation.md b/pending-approval/gemini-key-rotation.md
new file mode 100644
index 00000000..74b290fb
--- /dev/null
+++ b/pending-approval/gemini-key-rotation.md
@@ -0,0 +1,80 @@
+# GATED: Leaked Gemini API key — env-ify + rotation
+
+**Owner:** vp-dw-commerce · **Drafted:** 2026-06-23 · **Status:** AWAITING STEVE'S GO
+**Severity:** 🔴 High — live plaintext Gemini API key committed to git (Mac2 + Kamatera), in history.
+
+## What's leaked
+
+A Gemini API key (prefix `AIza…`, last-4 **`ejMo`**, sha256-prefix `db13094b`) is hardcoded
+in tracked source. It is the **DW image-enrichment** key (referenced as `GEMINI_KEY` /
+`GEMINI_API_KEY` in the vendor-command-center + enrichment scripts), and it is the same key
+hardcoded around line ~45 of the Kamatera prod cron `shopify-priority-enrichment.py`.
+
+A **second** Gemini key (last-4 **`S2ic`**, sha256-prefix `04096707`) is leaked in two
+non-DW projects — fold into the same rotation pass.
+
+### Leaked-literal consumers found (read-only scan of ~/Projects, last-4 only — full key NEVER echoed)
+
+| File | Line | Key (last-4) |
+|---|---|---|
+| Designer-Wallcoverings/DW-Agents/vendor-command-center/logo-cropper.js | 11 | …ejMo |
+| Designer-Wallcoverings/DW-Agents/vendor-command-center/website-scorer.js | 21 | …ejMo |
+| Designer-Wallcoverings/DW-Agents/vendor-command-center/standardization-worker.js | 19 | …ejMo |
+| goodquestion-ai/scripts/sensitive_patterns.py | 232 | …ejMo |
+| dw-boardroom-v2/ecosystem.config.cjs | 11 | …S2ic |
+| goodquestion-ai/scripts/generate-hero-images.cjs | 10 | …S2ic |
+| **Kamatera** /…/shopify-priority-enrichment.py (NOT on Mac2) | ~45 | …ejMo |
+
+Both leaked literals are **orphans** — neither is the registry master `GEMINI_API_KEY`
+(…-mvA, an `AQ.A`-format key) nor `GEMINI_API_KEY_WALLCO` (…k720). So they were never routed
+through the secrets manager. **Do NOT converge onto wallco's dedicated …k720 key** (prod-separate).
+
+## Why this is gated (NOT auto-executed)
+
+- **Google-console revoke + new-key issue** = identity/credential action → Steve runs it.
+- **git-history rewrite** (filter-repo) = destructive/irreversible → Steve runs it.
+- Env-ifying the source to read a registry var that doesn't exist yet would *break* the scripts,
+ so env-ify must happen **after** the new key is imported. Doing it as one approved sequence is
+ cleaner than a half-applied state. Nothing below has been executed.
+
+## Approved-sequence runbook (Steve executes the gated steps)
+
+**1. Revoke + reissue (Steve, Google AI Studio / console)** — revoke both leaked keys
+(…ejMo and …S2ic); issue a fresh key (or two, if you want enrichment vs boardroom separated).
+
+**2. Import new key(s) into the secrets registry (env-ify enablement):**
+```sh
+# choose the canonical alias for the DW enrichment key:
+node ~/Projects/secrets-manager/cli.js add GEMINI_API_KEY_DW_ENRICH "<new-key>" # validates via Gemini verify endpoint, fans to all routes
+# (add a routes.json entry first if absent — destinations inferred below)
+```
+Routes the DW enrichment key should fan to (Mac2): the 4 DW files above read it as
+`process.env.GEMINI_KEY` (vendor-command-center) / `GEMINI_API_KEY`. Register those .env targets.
+
+**3. Env-ify the source (code hygiene — reversible; can run via `/secret-strip` once key is in registry):**
+Replace each hardcoded literal with an env read. Example for the vendor-command-center files
+(they use `const GEMINI_KEY = '<literal>'`):
+```js
+const GEMINI_KEY = process.env.GEMINI_KEY || process.env.GEMINI_API_KEY_DW_ENRICH;
+if (!GEMINI_KEY) throw new Error('GEMINI_KEY not set — route via /secrets');
+```
+Python (`sensitive_patterns.py:232`): `GEMINI_KEY = os.environ["GEMINI_API_KEY_DW_ENRICH"]`.
+`/secret-strip` automates this fleet-wide (it's installed; gitleaks pre-commit hooks present in the DW repo).
+
+**4. Redeploy the Kamatera cron** with the same env-ify (the file is on Kamatera only; backup
+`.bak-20260623151824` exists there). On Kamatera, source the key from `/root/.env` in the cron
+wrapper (the dotenv-in-cron pattern) rather than a literal. Smoke-test green after.
+
+**5. git-history scrub (Steve — destructive):** the old key is in git history on both Mac2 repos
+and Kamatera. After rotation the old key is dead, so this is hygiene not emergency, but to fully
+purge: `git filter-repo --replace-text <(echo 'AIza…ejMo==>REDACTED')` per repo, then force-push
+**only if Steve explicitly approves a force-push** (default: local rewrite, no push).
+
+## Steve, paste to proceed
+- [ ] Revoked …ejMo and …S2ic at Google + issued new key(s)
+- [ ] New key value (so the import in step 2 can run) — or you run step 2 yourself
+- [ ] Approve env-ify of the 6 Mac2 files via /secret-strip (reversible)
+- [ ] Approve Kamatera cron redeploy
+- [ ] Approve (or decline) git-history rewrite + whether any force-push is allowed
+
+**$ cost:** $0 (local scans + edits). Gemini verify-endpoint call on import ≈ $0 (free tier ping).
← c40bab9f Cap Gemini thinking budget (thinkingBudget=0) on remaining u
·
back to Designer Wallcoverings
·
Designtex unit_of_measure audit: 71/302 say 'Priced Per Sing 9717a88a →