7626f1b496
Security audit fixes (see SECURITY_AUDIT.md): - lib/tiers.ts: checkAndIncrementTierLimit's recipe/storage branches did a live count/sum check with no lock tying it to the later write, so two concurrent requests near the cap could both pass and both write past the limit. Added checkTierLimitInTransaction — holds a per-user Postgres advisory lock for the duration of the caller's transaction, so the check and the write are atomic together. Applied to every recipe/storage write path (recipes create/update, fork, rate, avatar, and 7 AI recipe-creation routes). - Adversarial re-verification of that fix caught a bigger gap in the same area: four AI routes (photo import, idea generation, batch-cook, translate-to-new-draft) had no recipe-limit check at all. Fixed. - Added missing per-user rate limits to 5 AI endpoints (adapt, drinks, pairings, translate, variations) that had none, unlike their siblings. - search page now checks for a session server-side, matching every other page under (app)/ — defense in depth; the underlying API was already public by design and proxy.ts already blocked unauthenticated requests. - admin/settings route now uses the shared requireAdmin instead of a local duplicate. - Documented two admin support-ticket endpoints missing from the OpenAPI spec; verified full route/OpenAPI parity otherwise. - Bumped drizzle-orm to fix a SQL-identifier-escaping CVE, and overrode two transitive deps (esbuild, postcss) with known CVEs. pnpm audit is clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
38 lines
3.3 KiB
Markdown
38 lines
3.3 KiB
Markdown
# Follow-up: dependency CVEs + OpenAPI coverage
|
|
|
|
Companion to `SECURITY_AUDIT.md` (same day, same session). Two additional checks requested after the tier-limit/rate-limit fixes shipped.
|
|
|
|
## 1. Dependency vulnerabilities (`pnpm audit`)
|
|
|
|
**Before:**
|
|
|
|
| Severity | Package | Issue | Fixed in |
|
|
|---|---|---|---|
|
|
| High | `drizzle-orm@0.44.7` | SQL injection via improperly escaped SQL identifiers ([GHSA-gpj5-g38j-94v9](https://github.com/advisories/GHSA-gpj5-g38j-94v9)) | `>=0.45.2` |
|
|
| Moderate | `esbuild@0.18.20` (transitive, via `drizzle-kit` → `@esbuild-kit/esm-loader`, dev-only) | esbuild dev server accepts requests from any origin ([GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99)) | `>=0.24.3` |
|
|
| Moderate | `postcss@8.4.31` (transitive, via `next@16.2.9`) | XSS via unescaped `</style>` in CSS stringify output ([GHSA-qx2v-qp2m-jg93](https://github.com/advisories/GHSA-qx2v-qp2m-jg93)) | `>=8.5.10` |
|
|
|
|
**Fix:**
|
|
- Bumped `drizzle-orm` to `^0.45.2` directly in `apps/web/package.json` and `packages/db/package.json` (it was a top-level dependency in both, not just transitive — straightforward version bump, no breaking API changes hit typecheck/tests/build).
|
|
- Added `overrides` in `pnpm-workspace.yaml` (pnpm 11 moved this out of `package.json`'s `pnpm.overrides`, which is silently ignored — that field was removed) forcing `esbuild: ">=0.24.3"` and `postcss: ">=8.5.10"` across the whole dependency tree, collapsing the vulnerable transitive copies into already-present patched versions (both packages already had a patched instance installed for other consumers — this just eliminates the vulnerable *second* copy rather than introducing a new major version).
|
|
|
|
**After:** `pnpm audit` → `No known vulnerabilities found`.
|
|
|
|
**Verification:** full re-run of `pnpm typecheck`, `pnpm exec vitest run` (191/193 passing — the 2 failures are the same pre-existing, unrelated baseline failures noted throughout this session), and `pnpm build` (production build succeeds, including the Tailwind/PostCSS pipeline under the new override) — all clean after the bump + overrides.
|
|
|
|
## 2. OpenAPI documentation coverage
|
|
|
|
Cross-referenced every `route.ts` under `apps/web/app/api/v1/**` (which HTTP methods each file exports) against every `registry.registerPath({ method, path, ... })` call in `apps/web/lib/openapi.ts`.
|
|
|
|
**Before:** two endpoints existed with zero OpenAPI documentation:
|
|
- `GET /api/v1/admin/support` — list all support tickets (admin only)
|
|
- `PATCH /api/v1/admin/support/{id}` — update a ticket's status, or retry its Gitea issue creation (admin only)
|
|
|
|
Everything else (109 other route/method pairs) was already documented, and there were no stale entries (documented paths with no matching route file).
|
|
|
|
**Fix:** added `AdminSupportTicketRef` / `UpdateAdminSupportTicketRef` schemas and both `registerPath` entries to `lib/openapi.ts`, next to the existing `admin/reports` entry, matching the response/error shapes actually returned by the two route handlers.
|
|
|
|
**After:** re-ran the cross-reference — full parity. The only "missing" entry is `GET /api/v1/openapi.json` itself, which doesn't need to self-document.
|
|
|
|
**Verification:** `pnpm typecheck` and `pnpm exec vitest run` clean after the addition (the new refs slot into the existing Zod-based OpenAPI registry with no schema conflicts).
|