# FarmaFinder Security Hotfixes Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Remove production-blocking secret, access-control, network-exposure, and dependency risks identified by the 2026-07-22 security audit. **Architecture:** Make production configuration fail closed, centralize service authentication for parapharmacy ingestion operations, and keep internal infrastructure private behind the reverse proxy. Upgrade dependency families in isolated batches with lockfile and runtime verification. **Tech Stack:** Node.js 20/24, Express, express-session, MongoDB/Mongoose, Docker Compose, npm lockfiles, Python/Pydantic settings, Jest/Vitest. --- ## Files and responsibilities - Modify `apps/backend/server.js`: production configuration validation, secure session cookie defaults, and any shared service-auth helper integration. - Create `apps/backend/src/config/required-env.js` and `apps/backend/src/middleware/service-auth.js`: fail-closed environment validation and constant-time service-key verification. - Modify `apps/parapharmacy-api/src/server.js`, `apps/parapharmacy-api/src/routes/products.js`, and `apps/parapharmacy-api/src/routes/scraper.js`: protect mutation/scrape routes, tighten limits, and hide Swagger in production. - Modify `docker-compose.yml` and `apps/pip-platform/docker-compose*.yml`: remove secret fallbacks, stop publishing internal ports, and pin image/dependency behavior. - Modify `apps/pip-platform/src/infrastructure/config/settings.py`: reject placeholder production secrets and wildcard credentialed CORS. - Modify `apps/backend/.env.example`, `.env.example`, and relevant README/docs: document required secret generation without real values. - Add/extend `apps/backend/__tests__/server.test.js` and create `apps/parapharmacy-api/__tests__/security.test.js`: regression coverage for fail-closed behavior and route protection. - Update relevant `package.json` and lockfiles only through package-manager commands after the security tests are in place. ### Task 1: Rotate and inventory credentials before code changes **Files:** Deployment secret store and local ignored `.env` files; no repository source changes required. - [ ] Revoke the Expo access token found in the local environment and issue a replacement with the minimum project scope. - [ ] Generate a new VAPID key pair and replace both public/private values wherever deployed. - [ ] Rotate `SESSION_SECRET`, `PG_PASSWORD`, `REDIS_PASSWORD`, `N8N_PASSWORD`, `INGEST_API_KEY`, MongoDB credentials, and PIP `JWT_SECRET_KEY` if their values were used outside local development. - [ ] Search deployment logs, CI variables, shell history, and backups for the old values; record the revocation date without writing secret values to Git. - [ ] Confirm `git ls-files` contains no actual `.env` file before continuing. ### Task 2: Add fail-closed production configuration validation **Files:** Create `apps/backend/src/config/required-env.js`; modify `apps/backend/server.js`, `apps/pip-platform/src/infrastructure/config/settings.py`, and both PIP Compose files. - [ ] Add a backend validator that rejects production startup when `SESSION_SECRET`, `CORS_ORIGIN`, and `PG_URL`/`PG_PASSWORD` are missing or equal to a known placeholder. Use `crypto.timingSafeEqual` only for fixed-length key comparisons; validation itself should compare exact placeholder strings. - [ ] Replace the backend fallback at `server.js:84` with a required value from the validator. - [ ] Set `cookie.secure` to `true` whenever `NODE_ENV === 'production'`, while retaining an explicit development override only for local HTTP. - [ ] Replace every Compose `${SECRET:-placeholder}` expression with `${SECRET:?SECRET must be set}` for production-required secrets. - [ ] In PIP settings, reject `JWT_SECRET_KEY=change-me-in-production`, reject default database/broker credentials in production, and reject `CORS_ORIGINS=['*']` when credentials are enabled. - [ ] Add tests that start configuration with missing/placeholder secrets and assert a clear startup error. ### Task 3: Authenticate parapharmacy ingestion and admin mutation routes **Files:** Create `apps/parapharmacy-api/src/middleware/service-auth.js`; modify `apps/parapharmacy-api/src/server.js`, `src/routes/products.js`, and `src/routes/scraper.js`; create `apps/parapharmacy-api/__tests__/security.test.js`. - [ ] Require `INGEST_API_KEY` for `POST /api/products`, `POST /api/products/bulk`, and `POST /api/scrape` using `Authorization: Bearer ` or a dedicated internal header. Reject missing/malformed keys with 401 and compare supplied keys in constant time. - [ ] Require a separate admin credential for `PUT /api/products/:id` and `DELETE /api/products/:id`; do not reuse a public frontend session unless the API is intentionally integrated with that session. - [ ] Add a route-specific limiter for `/api/scrape`, cap queries/sources to bounded arrays, cap product bulk size, and lower `express.json` to the smallest limit required by real payloads. - [ ] Return `{ error: 'Scraping failed' }` without `error.message` in production. - [ ] Mount Swagger only when `NODE_ENV !== 'production'` or protect it with the same admin control. - [ ] Test 401 for unauthenticated mutation/scrape requests, 403/401 for invalid keys, and successful behavior for a valid key. Test that public GET search endpoints remain available. ### Task 4: Close infrastructure network exposure **Files:** Modify `docker-compose.yml`, `apps/pip-platform/docker-compose.yml`, `apps/pip-platform/docker-compose.runtime.yml`, and `apps/frontend/nginx.conf` as needed. - [ ] Remove host `ports` for Redis, PostgreSQL, MongoDB, exporters, and n8n; use `127.0.0.1:host:container` only when local operator access is explicitly required. - [ ] Publish only the intended frontend/reverse-proxy port and route internal API traffic through the proxy or a private Docker network. - [ ] Add a dedicated internal network and keep database/exporter services off any public-facing network. - [ ] Add production security headers at the reverse proxy, including HSTS only when HTTPS is guaranteed, and verify proxy headers are preserved. - [ ] Disable or protect `/api/docs` in production and verify an external request cannot reach n8n, MongoDB, PostgreSQL, Redis, or exporter ports. ### Task 5: Make builds reproducible and remove mutable image inputs **Files:** `apps/backend/Dockerfile`, `apps/parapharmacy-api/Dockerfile`, `docker-compose.yml`, PIP Compose files, CI workflow files. - [ ] Replace `npm install --omit=dev` in the parapharmacy Dockerfile with `npm ci --omit=dev`. - [ ] Pin all runtime image tags to approved versions and digests; record the update date in the deployment documentation. - [ ] Add CI checks for `npm ci`, `npm audit --audit-level=high`, image vulnerability scanning, and secret scanning. - [ ] Generate a Python lockfile and run `pip-audit` or `uv audit` against resolved dependencies. ### Task 6: Upgrade vulnerable dependency families in batches **Files:** `package.json`, `package-lock.json`, each app `package.json`/lockfile touched by the audit. - [ ] First update patch/minor-compatible vulnerable transitive packages and regenerate lockfiles with `npm install --package-lock-only`; inspect the diff for unrelated upgrades. - [ ] Upgrade backend OpenTelemetry packages as one compatible family, then `bcrypt`/SQLite-related packages, and rerun backend tests. - [ ] Upgrade parapharmacy API `mongoose`/`fast-uri` and transitive packages, then rerun API security tests. - [ ] Upgrade frontend Vite/Rollup/esbuild and Vitest. Keep Vitest UI disabled in production and verify no UI server is started by CI or deployment. - [ ] Upgrade scraper dependencies and confirm Puppeteer still uses the intended Chromium binary. - [ ] Re-run `npm audit --json` for the workspace and each lockfile; document any accepted residual advisory with package, path, exploitability, and owner. ### Task 7: Verification gate before deployment **Files:** No source changes unless verification exposes a regression. - [ ] Run `git diff --check`. - [ ] Run backend tests: `npm test --prefix apps/backend`. - [ ] Run frontend tests: `npm test --prefix apps/frontend`. - [ ] Run the parapharmacy security tests and all available package tests. - [ ] Render Compose configuration with production-like variables and confirm no placeholder values remain: `docker compose config`. - [ ] Build every production image with lockfile-enforced installs. - [ ] Run a black-box smoke test proving public GET endpoints work, protected mutations return 401 without a key, and internal infrastructure is not host-published. - [ ] Re-run secret scanning and `npm audit --audit-level=high`; block deployment on any critical/high issue without an explicit documented exception.