security: harden production configuration and routes
Run Tests on Branches / Detect Changes (push) Successful in 12s
Run Tests on Branches / Frontend Tests (push) Successful in 2m12s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Successful in 2m2s
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
Run Tests on Branches / Backend Tests (push) Successful in 2m8s
Run Tests on Branches / Detect Changes (push) Successful in 12s
Run Tests on Branches / Frontend Tests (push) Successful in 2m12s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Successful in 2m2s
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
Run Tests on Branches / Backend Tests (push) Successful in 2m8s
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# FarmaFinder Security Audit Report
|
||||
|
||||
**Audit date:** 2026-07-22
|
||||
**Scope:** repository source, configuration, environment files present on disk, Docker Compose files, Git history, Node lockfiles, and Python dependency declarations.
|
||||
**Status:** **Not ready for an unrestricted production deployment.**
|
||||
|
||||
## Executive summary
|
||||
|
||||
The most urgent risks are configuration and access-control issues, not evidence of a secret committed to Git:
|
||||
|
||||
1. Local ignored `.env` files contain credential-shaped production values. The values must be treated as exposed if they were ever copied to a server, shared, or used in a public environment. Rotate the Expo access token and VAPID private key immediately, and rotate any database, session, n8n, or webhook credentials that may have shared the same deployment.
|
||||
2. Production Docker Compose has known-secret fallbacks such as `change-me-in-production`, `change-me`, and `pip-secret`. A deployment can therefore start with predictable credentials when variables are missing.
|
||||
3. The parapharmacy API exposes product create, bulk upsert, update, delete, and scraper-trigger endpoints without authentication. This is a direct integrity and availability risk.
|
||||
4. The backend silently falls back to a hard-coded session secret. A missing secret must fail closed in production.
|
||||
5. The verified npm audit reports 79 advisories in the workspace, including 3 critical and 13 high. The most important direct production-adjacent findings include vulnerable OpenTelemetry packages, `bcrypt`/`tar` transitive issues, and the vulnerable `ws`/`brace-expansion` chains. The frontend test toolchain includes a critical Vitest advisory; it must not be exposed as a server in any environment.
|
||||
|
||||
## Findings
|
||||
|
||||
### F-01 — Secrets present in local environment files
|
||||
|
||||
**Severity:** Critical
|
||||
**Evidence:** `apps/backend/.env` and `apps/parapharmacy-api/.env` exist locally and are ignored by Git. The backend file contains a non-empty Expo access token and VAPID private key; it also contains database/session/ingest credential fields. Values are intentionally not reproduced here.
|
||||
|
||||
**Impact:** Push credentials, session signing, database access, or workflow ingestion may be compromised. A VAPID private key can impersonate the application for web push; an Expo token can send notifications through the project account.
|
||||
|
||||
**Action:** Rotate the Expo token and VAPID key now. Rotate all non-development credentials in those files. Review CI, deployment hosts, shell history, password managers, and logs for copies. Keep secrets in the deployment secret store only.
|
||||
|
||||
### F-02 — Predictable production secret fallbacks
|
||||
|
||||
**Severity:** Critical
|
||||
**Evidence:** `docker-compose.yml:12,34,41,89,137,141,147,176,178` uses defaults including `change-me-in-production`, `change-me`, and a derived PostgreSQL URL. `apps/backend/server.js:83-85` falls back to `farma-clic-secret-key-change-in-production`. `apps/pip-platform/src/infrastructure/config/settings.py:16,24,26` contains default database, broker, and JWT credentials. The PIP Compose files also default `JWT_SECRET_KEY` at `apps/pip-platform/docker-compose.yml:13` and `docker-compose.runtime.yml:13`.
|
||||
|
||||
**Impact:** Missing environment injection can enable session forgery, JWT forgery, database access, or n8n takeover.
|
||||
|
||||
**Action:** Remove secret defaults. Add startup validation that rejects `NODE_ENV=production`/production deployments when required secrets are absent or match known placeholders. Use `${VAR:?VAR must be set}` in Compose for required values.
|
||||
|
||||
### F-03 — Unauthenticated parapharmacy write/delete/scrape APIs
|
||||
|
||||
**Severity:** Critical
|
||||
**Evidence:** `apps/parapharmacy-api/src/routes/products.js:280-320,340-390` exposes bulk write, update, and delete routes without auth. `apps/parapharmacy-api/src/routes/scraper.js:7-24` exposes a scraper trigger without auth. `apps/parapharmacy-api/src/server.js:55-70` applies only global CORS, JSON parsing, logging, and rate limiting.
|
||||
|
||||
**Impact:** An unauthenticated caller can poison or delete the catalog, trigger expensive Puppeteer scraping, and cause resource exhaustion.
|
||||
|
||||
**Action:** Protect write/delete/scrape routes with a dedicated ingestion/admin API key or service-to-service authentication. Apply a strict body/item limit and a separate low-rate limiter to scraper execution. Return generic errors without echoing scraper exception messages.
|
||||
|
||||
### F-04 — Hard-coded backend session secret fallback
|
||||
|
||||
**Severity:** High
|
||||
**Evidence:** `apps/backend/server.js:83-85` uses a fixed fallback secret. The session cookie is HTTP-only and SameSite=Lax (`:87-91`), which is good, but `secure` is opt-in at `COOKIE_SECURE=true`.
|
||||
|
||||
**Impact:** Anyone who knows the repository can forge sessions when the deployment omits `SESSION_SECRET`; if `COOKIE_SECURE` is omitted in HTTPS production, cookies may be sent over an accidental HTTP path.
|
||||
|
||||
**Action:** Fail startup when production lacks a strong `SESSION_SECRET`; force secure cookies in production and set `app.set('trust proxy', ...)` only to the known proxy topology.
|
||||
|
||||
### F-05 — Public infrastructure ports and unauthenticated observability/admin surfaces
|
||||
|
||||
**Severity:** High
|
||||
**Evidence:** `docker-compose.yml:29-30,66-67,75-76,86-89,102-103,122-123,131-132` publishes backend, frontend, exporters, parapharmacy API, MongoDB, and n8n ports. Swagger is mounted at `/api/docs` in `apps/parapharmacy-api/src/server.js:64-69` without an environment guard.
|
||||
|
||||
**Impact:** Databases, exporters, n8n, and internal APIs may be reachable from the host network or internet. Swagger reveals mutation endpoints and operational details.
|
||||
|
||||
**Action:** Bind internal services to the Docker network or loopback only. Publish only the reverse proxy/frontend. Restrict n8n and Swagger to an authenticated admin network or disable them in production.
|
||||
|
||||
### F-06 — Verified npm dependency advisories
|
||||
|
||||
**Severity:** Critical/High/Moderate by package and exposure
|
||||
**Evidence:** `npm audit --json` completed with network access on 2026-07-22.
|
||||
|
||||
| Lockfile / scope | Critical | High | Moderate | Low | Total |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| Workspace root | 3 | 13 | 60 | 3 | 79 |
|
||||
| Backend | 1 | 11 | 41 | 3 | 56 |
|
||||
| Frontend | 1 | 3 | 18 | 0 | 22 |
|
||||
| Parapharmacy API | 0 | 2 | 0 | 1 | 3 |
|
||||
| Scraper | 0 | 1 | 0 | 0 | 1 |
|
||||
|
||||
Notable verified chains include:
|
||||
|
||||
- backend: `@opentelemetry/auto-instrumentations-node` high-severity Prometheus exporter crash advisory; `bcrypt` through `@mapbox/node-pre-gyp`/`tar`; vulnerable `ws` and `uuid` transitive chains;
|
||||
- frontend: critical `vitest` advisory when its UI server is exposed, plus vulnerable Vite/esbuild/Rollup and Grafana Faro/OpenTelemetry chains;
|
||||
- parapharmacy API: `fast-uri`, `brace-expansion`, and `body-parser` advisories;
|
||||
- scraper: `brace-expansion` high-severity DoS advisory.
|
||||
|
||||
**Action:** Apply targeted non-breaking patches first where available, then upgrade major-version families in isolated branches with tests. Do not use `npm audit fix --force` blindly; the audit indicates major-version changes for several fixes.
|
||||
|
||||
### F-07 — Dependency hygiene and likely-unused candidates
|
||||
|
||||
**Severity:** Medium (maintenance/security surface)
|
||||
**Evidence:** A static repository scan found direct dependencies with no source import/reference outside manifests/lockfiles:
|
||||
|
||||
- backend: `barcode-detector`, `@opentelemetry/exporter-logs-otlp-grpc`, `@opentelemetry/sdk-logs`, `@opentelemetry/sdk-trace-base`;
|
||||
- frontend: `@grafana/faro-web-sdk`;
|
||||
- mobile: `expo-dev-client`, `expo-linking`, `react-native-screens`, `react-native-worklets` (some may be required by Expo/native autolinking);
|
||||
- parapharmacy API: `jest`, `supertest` (test tooling is declared but no tests were found in that package).
|
||||
|
||||
This scan is not proof of unused status because Expo, native autolinking, configuration, and instrumentation can consume packages indirectly. Confirm each candidate with package-manager dependency tracing and a clean build before removal. No package was removed during this audit.
|
||||
|
||||
### F-08 — Build/runtime supply-chain hygiene
|
||||
|
||||
**Severity:** High
|
||||
**Evidence:** `docker-compose.yml:22,57,73,84,95,120,129,169` uses mutable `:latest` image tags. `apps/parapharmacy-api/Dockerfile` uses `npm install --omit=dev` instead of `npm ci`; `apps/backend/Dockerfile` uses `npm ci`.
|
||||
|
||||
**Impact:** Rebuilds are not reproducible and can silently pull changed or compromised images/dependency resolutions.
|
||||
|
||||
**Action:** Pin images by version and digest, use lockfile-enforced `npm ci` for every Node image, and add image/dependency scanning to CI.
|
||||
|
||||
### F-09 — Mobile/API keys and telemetry endpoints need restriction
|
||||
|
||||
**Severity:** Medium
|
||||
**Evidence:** `apps/frontend-mobile/google-services.json:18` contains a Firebase API key. This type of key is normally public, but must be restricted by package/bundle identity and API scope in Google Cloud/Firebase. Mobile and frontend env examples point telemetry at public or host endpoints.
|
||||
|
||||
**Action:** Verify Firebase key restrictions, avoid treating public client configuration as a secret, and enforce collector authentication/rate limits so telemetry endpoints cannot be abused.
|
||||
|
||||
## Positive controls observed
|
||||
|
||||
- Git status was clean before this audit.
|
||||
- `.gitignore` excludes `.env`, dependency directories, build output, and Android signing material.
|
||||
- Git history inspection found environment examples and placeholder values, but no tracked actual `.env` file or the local Expo/VAPID values.
|
||||
- Backend uses parameterized SQL for the inspected user/session paths, bcrypt password hashing, HTTP-only cookies, admin middleware, and route-specific rate limiting.
|
||||
- Production backend and frontend use container builds, and backend uses `npm ci --omit=dev`.
|
||||
|
||||
## Verification and limitations
|
||||
|
||||
- Source/configuration and Git-history checks were read-only.
|
||||
- Online npm audit was executed with network access on 2026-07-22; advisory counts are a point-in-time result and should be rerun in CI.
|
||||
- No production host, running container, database, secret manager, cloud account, or external firewall was inspected.
|
||||
- No Python lockfile exists for `apps/pip-platform`; the Python audit therefore covered declarations and defaults, not resolved CVEs. Add a lockfile and run `pip-audit`/`uv audit` in CI.
|
||||
- The audit did not prove that every endpoint is unreachable externally; exposure depends on deployment networking.
|
||||
|
||||
## Recommended deployment decision
|
||||
|
||||
Do not deploy the current configuration publicly until F-01 through F-05 are addressed. Dependency upgrades and supply-chain pinning should follow immediately. The implementation sequence is documented in [the hotfix plan](../superpowers/plans/2026-07-22-security-hotfixes.md).
|
||||
Reference in New Issue
Block a user