← back to Codex Review 2026 04 30
_PRIORITY_PATCHES.md
203 lines
# Priority patches Steve can apply in the morning
These are concrete diffs/commands Claude generated tonight from the deferred lists. Each is verified read-only safe — Steve applies, Claude doesn't auto-apply.
## 🚨 P0 — LIVE Anthropic API keys hardcoded in source (**rotate immediately**)
Late-night Claude grep surfaced these. Files contain literal `sk-ant-api03-...` keys, some without env fallback. Five distinct keys leaked across 11 files. Locations (see `_SECRETS_INLINE.md` for full list):
```
~/Projects/Designer-Wallcoverings/DW-Programming/KravetDesignTagger/server.js:12
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/dwjs-ai-retag.ts:21
~/Projects/Designer-Wallcoverings/DW-Programming/update-specific-schumacher.ts:13
~/Projects/Designer-Wallcoverings/DW-Programming/schumacher-dwsw-full-updater.ts:19
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/fix-all-dwpd-colors.ts:15
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/fix-dwjs-red-tags.ts:17
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/fix-color-tags.ts:14
~/Projects/Kamatera/dear-bubbe-nextjs/ecosystem.config.js:10
~/Projects/Kamatera/DW-Agents/bob-the-blogger/server.js:33
~/Projects/Kamatera/DW-Agents/thibaut-agent/server.js:17 (no env fallback at all — inline)
```
**Action**: rotate all 5 Anthropic keys at https://console.anthropic.com/settings/keys, then use `/secrets` skill to fan the new key into the env files. Then sed-replace the inline literals with `process.env.ANTHROPIC_API_KEY` and remove the fallback (fail-fast pattern).
## 🚨 P0 — LIVE Gemini API keys in 14+ files (rotate immediately)
Same key (`${GOOGLE_API_KEY}`) repeated across:
```
~/Projects/Bertha/kalshi-dash/server.js:130
~/Projects/SDCC-Stories/lib/gemini.js:8
~/Projects/sku-check-skill/server.js:25
~/Projects/Designer-Wallcoverings/gemini-classify-texture.js:6
~/Projects/Designer-Wallcoverings/gemini-enrich-arte.js:4
~/Projects/Designer-Wallcoverings/enrich-remaining-13.js:5
~/Projects/Designer-Wallcoverings/gemini-enrich-gaps.js:5
~/Projects/Designer-Wallcoverings/gemini-enrich-arte9.js:4
~/Projects/Designer-Wallcoverings/arte-fill-tags.js:5
~/Projects/Designer-Wallcoverings/ai-enrich-gaps2.js:5
~/Projects/Designer-Wallcoverings/ai-enrich-arte-fix.js:4
~/Projects/Designer-Wallcoverings/enrich-arte-gaps.js:4
~/Projects/Designer-Wallcoverings/enrich-arte-puppeteer.js:5
```
Plus a 2nd key `${GOOGLE_API_KEY}` in `~/Projects/SDCC-Stories/lib/gemini.js:9`.
**Action**: rotate both at https://aistudio.google.com/app/apikey, sed-replace literals with `process.env.GEMINI_API_KEY`.
## 🚨 P0 — LIVE Shopify admin token hardcoded in **18+ files** (single token mass leak)
Token `shpat_REDACTED` appears in:
```
~/Projects/archive-agent/server.js:15 (env-fallback)
~/Projects/archive-agent/ecosystem.config.js:10 (raw in pm2 env block)
~/Projects/Letsbegin/migrate_global_to_custom.js:29 (inline, no env)
~/Projects/dw-war-room/vite.config.ts:8 (inline, no env)
~/Projects/dwjs-consolidation-2026-04-23/*.js (15+ one-off scripts, all inline)
```
**Action**: rotate at Shopify admin → Apps → Develop apps → rotate the admin API token. Then sed-replace literals with `process.env.SHOPIFY_ADMIN_TOKEN` (fail-fast on missing). The dwjs-consolidation scripts are dated 2026-04-23 one-offs — consider archiving the whole dir + redacting tokens before git-committing anywhere.
## 🚨 P0 — LIVE Slack tokens in 9+ files (incl. dangerous **user-scope** token)
Three distinct tokens, all in Kamatera mirror + Designer-Wallcoverings DW-Programming:
```
${SLACK_BOT_TOKEN} (DWMCP bot, 5 files)
${SLACK_BOT_TOKEN} (Designer bot, 2 files)
${SLACK_USER_TOKEN}-redacted-NEEDS-ROTATION-2026-05-07 (USER scope, 2 files — dangerous, can read DMs)
```
Files include:
```
~/Projects/Kamatera/Designer-Wallcoverings-scripts/activate-koroseal-cron.js:11
~/Projects/Kamatera/Designer-Wallcoverings-scripts/activate-arte-cron.js:12
~/Projects/Kamatera/DW-Agents/slack-dm-viewer/server.js:34,36,40
~/Projects/Kamatera/DW-Agents/scripts/slack-bulk-delete.js:23,24,25
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/universal-completion-notifier.ts:9
~/Projects/Designer-Wallcoverings/DW-Programming/ImportNewSkufromURL/dwjs-ai-retag.ts:24
```
**Action**: revoke all 3 at https://api.slack.com/apps → respective app → OAuth & Permissions → "Revoke installation" or rotate. The xoxp- (user) token is highest risk — anyone with it can act as Steve in Slack. Re-issue as bot-scope where possible; user-scope only when truly needed.
## 🚨 P0 — LIVE Cloudflare API token (already in MEMORY.md)
```
~/Projects/philipperomano/finish_dns.sh:8
CF="${CLOUDFLARE_API_TOKEN:-yMyJ8CeD7zzXc0C3UxCHVwQG6QATAs6Kxuw6mn9C}"
```
Per `feedback_cf_token_leaked.md`: live CF token committed plaintext. DNS-edit only, no zone-create. Action: rotate at https://dash.cloudflare.com/profile/api-tokens → mint new account-scoped token, replace fallback.
## 🚨 P0 — Postgres password `DW2024SecurePass` for `dw_admin` leaked in 10+ files
This is the credential for the `dw_unified` PG database — the wallcoverings business core data store.
```
~/Projects/Bertha/kalshi-dash/server.js:351,4875
~/Projects/Bertha/react-dash/server.js:28
~/Projects/Bertha/src/lib/db.js:4
~/Projects/archive-agent/server.js:17 (env-fallback)
~/Projects/archive-agent/ecosystem.config.js:11 (raw in pm2 env block)
~/Projects/Letsbegin/scrape_dg_specs.js:12
~/Projects/timeout-agent/server.js:21 (uses :15432 tunnel port — Mac Studio 2)
~/Projects/fix-no-image-products.js:172 (one-off script)
~/Projects/fix-as-creation-17.js:99 (one-off script)
```
**Action**: rotate the `dw_admin` PG password (`ALTER USER dw_admin WITH PASSWORD '<new>';`). Update `.env` files via `/secrets` skill. Sed-replace inline literals with `process.env.DATABASE_URL` (fail-fast). Order matters: per memory, schema changes go Local-first → Kamatera publishes via logical replication; password is a server-side change so do it on Mac2 first, then update Kamatera env, then sync.
## 🚨 P0 — Vendor scraper passwords leaked (`*<service>access911*` pattern)
```
~/Projects/watches/server.js:85 AUTH_PASSWORD = 'DW2025Secure!'
~/Projects/watches/thibaut-description-backfill.js:22 password: '*Thibautaccess911*'
~/Projects/watches/thibaut-room-settings-scraper.js:13 THIBAUT_PASSWORD = '*Thibautaccess911*'
~/Projects/dear-bubbe-nextjs/lib/instagram-poster.js:15 INSTAGRAM_PASSWORD: '*Instaaccess911*'
~/Projects/dear-bubbe-nextjs/archived/social-posters/* 4 more files with Bluesky/Twitter/Instagram '*<svc>access911*' pattern
~/Projects/sku-check-skill/server.js:31 YORKWALL_PASSWORD = '*Brewsteraccess911*'
~/Projects/Kamatera/dear-bubbe-nextjs/lib/instagram-poster.js:15 (mirror)
~/Projects/Kamatera/kamatera-claude-skills/resize-it/server.py:22 SPOONFLOWER_PASSWORD = '*Spoonaccess911*' (Kamatera mirror)
```
**Action**: rotate ALL of these at their respective vendor sites (Thibaut, Instagram, Bluesky, Twitter, Yorkwall/Brewster, Spoonflower). The `*<service>access911*` pattern is so consistent that anyone seeing ONE password can probably guess the others. After rotation, switch to a per-service env var (no fallback literal) and consider random-generated passwords stored in 1Password.
## 🚨 P0 — `room-setting-agent` (LIVE pm2) password is `DW2025Secure!` literally written in source comment
```
~/Projects/Kamatera/DW-Programming/room-setting-app/app/api/auth/login-password/route.ts:8
~/Projects/Designer-Wallcoverings/DW-Programming/room-setting-app/app/api/auth/login-password/route.ts:8
```
```ts
// Hardcoded hash for DW2025Secure! (bcrypt hash with special chars that env vars can't handle)
const AUTH_PASSWORD_HASH = process.env.AUTH_PASSWORD_HASH || '$2b$10$GXL6hj.1OAdCJ7tDSPYIPuhJxq/MgIYynNyAFdqfrwG9T4yImb3H.';
```
Confirmed via `pm2 env 11` — `AUTH_PASSWORD_HASH` is **NOT set in pm2 env**, so the inline default IS what's used at runtime. Anyone reading the source knows admin/DW2025Secure! gets in. The bcrypt hash is technically secure (10 rounds), but the comment renders that moot.
**Action**:
1. Pick a new password (e.g., `pwgen -s 24 1` or 1Password generator).
2. Generate fresh bcrypt: `node -e "console.log(require('bcrypt').hashSync(process.argv[1], 12))" '<NEW_PW>'`.
3. Set in pm2 env: edit `~/Projects/Kamatera/DW-Programming/room-setting-app/ecosystem.config.js` to set `AUTH_PASSWORD_HASH: '<new-hash>'`.
4. Remove the inline default + comment from `route.ts`.
5. `pm2 restart room-setting-agent --update-env` and `pm2 save`.
Note: the comment also leaks the production path `/root/Projects/Designer-Wallcoverings/DW-Programming/room-setting-app/data/login-log.json` — confirms this serves on Kamatera.
## P1 — bcrypt hashes inline (lower risk, dormant projects)
- `~/Projects/handbag-auth-nextjs/src/app/api/auth/login/route.ts:26,33` — 2 inline hashes. Project not running on pm2 (dormant). Still: if you ever spin it up, fix first.
- `~/Projects/dear-bubbe-admin/backend/routes/auth.js:11` — comment says `// password` next to a bcrypt hash. The hash format suggests the password is literally `password`. Project not running on pm2 (dormant). Still: don't reuse this code without rotating.
## P0 — `Designer-Wallcoverings/shopify/scripts/wm-*.js` hardcoded puppeteer path
Three scripts hard-require puppeteer from a sibling project's node_modules:
```js
// ~/Projects/Designer-Wallcoverings/shopify/scripts/wm-price-scrape-morris.js:8
// ~/Projects/Designer-Wallcoverings/shopify/scripts/wm-pattern-retry.js:8
// ~/Projects/Designer-Wallcoverings/shopify/scripts/wm-price-scrape.js:15
const puppeteer = require('/Users/stevestudio2/Projects/Designer-Wallcoverings/DW-Websites/GrassclothWallpaper.com/node_modules/puppeteer');
```
Why bad: if `GrassclothWallpaper.com/node_modules/` gets cleaned/reinstalled, these scripts break silently. Also breaks any CI/CD that doesn't have GrassclothWallpaper preinstalled.
Fix: install puppeteer in the shopify dir:
```bash
cd ~/Projects/Designer-Wallcoverings/shopify
npm install puppeteer-core --save # or full puppeteer if you need bundled chromium
# Then in each wm-*.js: const puppeteer = require('puppeteer-core');
```
## P0 — Stripe webhook secret enforcement (DEPLOY STEP)
The 3 next.js sites under `site-factory/sites/*.com/app/` have updated source but stale builds. Activate codex's fix:
```bash
for site in wholivedthere.com bubbesblock.com claimmyaddress.com; do
cd ~/Projects/site-factory/sites/$site/app
npm run build && pm2 restart site-${site%.com}
done
sleep 5
for p in 3001 3002 3003; do curl -s -o /dev/null -w ":$p %{http_code}\n" http://127.0.0.1:$p/; done
# Should still be 200 — the fix only changes behavior on missing STRIPE_WEBHOOK_SECRET
```
## P0 — am-recrawl one-shot misconfiguration (KAMATERA-SIDE)
Codex's POKE found scrape-andrewmartin.js + scraper-utils.js bugs. **Edit on Kamatera, not Mac.** Patch in `_PM2_NOTES.md`. Stop the local pm2 process from auto-starting on boot:
```bash
pm2 delete am-recrawl # currently stopped, but this removes from pm2 dump too
pm2 save
```
Then on Kamatera: apply the codex patch (idempotent closePool, browser.isConnected guards, throw on disconnect), and run as cron (not pm2-autorestart) for periodic recrawls.
## P1 — Done tonight (no action needed)
- ✓ `.gitignore` protection added to: resize-it, secrets-manager, wholivedthere/bubbesblock/claimmyaddress next.js apps, site-factory/admin
- ✓ `.env.example` template added to: secrets-manager (keys only, values redacted)
- ✓ sf-admin SESSION_SECRET wired in (96-char random) — survives next pm2 restart
## P1 — sf-admin SF_ADMIN_DEV=1 dev-bypass leak
`ecosystem.config.js:49` has `SF_ADMIN_DEV: '1'` which bypasses Google OAuth (auto-authenticates as Steve). The SESSION_SECRET fix Claude wired in tonight prevents session tampering, but anyone reaching :9883 still gets admin access in dev-bypass mode. Fix:
```js
// ~/Projects/site-factory/ecosystem.config.js:49
- SF_ADMIN_DEV: '1',
+ SF_ADMIN_DEV: '0', // require real Google OAuth
```
Then ensure GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET are set in the same env block.
(Note: sf-admin is bound to 127.0.0.1 only, so the dev-bypass leak is contained to local-machine attackers. Still worth fixing.)
## P2 — vf-orchestrator quirky restart pattern
visual-factory-orchestrator restarts every ~25min with exit code 0. Not a fire (autorestart catches it, HTTP 200 throughout) but worth understanding. Look for:
- `process.exit(0)` calls in server.js or stage runners
- Any `setInterval(..., 25*60*1000)` cleanup hook
- `pm2 reload` triggers from another cron/watcher
This is informational, not blocking.
## What's NOT in this list
- All the deferred items in per-project CHANGES.md `## Deferred (needs Steve)` sections — those need codex (not yet Claude-able) or domain knowledge Steve has.
- Schema/migration work for bankrupt-leads, professional-directory, lawyer-directory-builder — DDL is genuinely Steve-only.
- Authentication policy choices for public POST endpoints — needs Steve to decide token vs OAuth vs IP-allowlist (`NEEDS_AUTH.md` lists candidates).
- Codex round-3 attempts (15 projects) — blocked at quota; resume in the morning per `_QUOTA_HALT.md`.