Session 31: Code audit + security review — NFL MARKET_MAP gap fixed, npm audit 0 vulns (1695 tests)

- Add NFL keys to oddsNormalizer.MARKET_MAP (defensive; same silent-zero
  class as the Session 30 MLB bug) + NFL surface test
- npm audit fix: ws/qs + Supabase transitives, 7 vulns -> 0 (semver-safe)
- Audit findings documented in BUILD-STATE: grades cache has no writer,
  NFL/NHL not wired end-to-end, rate limiting only on /analyze, tests
  mutate a tracked jsonl, leaked GitHub PAT in origin remote (rotate)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-06-14 23:48:40 -04:00
parent a3351e2135
commit 2ba3958c7a
4 changed files with 186 additions and 33 deletions
+70
View File
@@ -4,6 +4,76 @@
2026-06-14
## Current Phase
AUDIT v31.0 — Full code audit + security review + cleanup (Session 31)
## Session 31 (2026-06-14) — SHIPPED (audit)
Full-codebase audit, not a feature build. Validated 30 sessions of
assumptions across the API→normalizer→cache→route→proxy→frontend chain.
Backend 1694 → **1695 tests** (+1), 137 suites, zero regressions. Web
build clean. `npm audit`: 7 vulns (3 high, 4 moderate) → **0**.
### FIXES APPLIED
1. **MARKET_MAP NFL gap (silent-failure class, same family as the MLB
bug Session 30 fixed).** `oddsNormalizer.MARKET_MAP` had ZERO NFL
keys — when NFL wires up (season approaching) every NFL prop would
normalize to nothing. Added defensive mappings for both odds-api
`_yds` and `_yards` spellings → internal stat_types aligned with
`config/statFilters.js` (passing_yards/rushing_yards/receiving_yards/
interceptions + pass/rush/reception TDs, receptions, anytime_td,
kicking_points). Additive/zero-risk (only fires when those markets
are returned). +1 explicit NFL surface test.
2. **`npm audit fix`** — resolved ws (uninitialized memory disclosure)
+ qs (DoS) + transitive Supabase deps, all semver-safe. 0 vulns.
### SECURITY AUDIT (Ryan Montgomery)
- Stripe webhook: ✅ verified via `stripe.webhooks.constructEvent`
(`stripeService.constructWebhookEvent`, signature + 400 on failure).
- CORS: ✅ allowlist (localhost, vyndr.app, *.vercel.app preview),
`FRONTEND_ORIGINS` override — NOT open `*`.
- Internal routes: ✅ `requireInternalAuth` via `router.use` on the whole
`/api/internal` router (VYNDR_INTERNAL_KEY).
- Hardcoded secrets in SOURCE: ✅ none (only doc-comment references).
- npm audit: ✅ 0 after fix.
- Supabase service-role: scoped to `src/utils/supabase.js` (backend-only;
Express enforces its own auth) — acceptable.
- 🔴 **CRITICAL (operator action): live GitHub PAT (`ghp_…`) embedded in
the `origin` remote URL in `.git/config`.** Not in tracked source (not
committed/pushed) but exposed on disk. ROTATE the token and scrub the
URL (use a credential helper). Not auto-fixed — needs rotation.
### FINDINGS DOCUMENTED (deliberately left)
- **`grades:{sport}` cache has NO writer.** `contentTemplateService`
collector reads it ("when present"), so content slate/POTD never reach
`dataLevel: 'full'` in prod — degrades to lines/schedule. Graceful by
design; wiring a grades-cache writer is feature work. Severity: medium.
- **NFL/NHL props not wired end-to-end.** `oddsService.SPORT_KEYS` has no
nfl/nhl; `proplineAdapter.MARKETS.nfl/nhl` are empty. Not a current
silent failure (nothing expects them yet). NFL MARKET_MAP now ready;
full wiring is feature work. NHL: no product support anywhere (absent
from statFilters/streaks) — left entirely.
- **Inbound rate limiting only on `/api/analyze`.** Public cached
endpoints (/odds, /schedule, /gamelines, /streaks) have no inbound
throttle. Real risk bounded (Redis-cached, no per-hit upstream cost).
Recommend adding the existing `middleware/rateLimit` to public routers.
- **Tests mutate a tracked file** (`data/training/resolutions-2026-06.jsonl`
gets resolution rows appended on every run → spurious git diff).
Reverted the artifact; logging path should write to a temp/ignored
location under test. Severity: low (hygiene).
- Cache keys VERIFIED aligned: oddsService writes `odds:{sport}:{UTC}`;
content `getBestLines` reads the same. No mismatches found.
- Edge cases already covered: PropLine unsupported-sport→null,
error→null, all-3-keys-exhausted→null, no-keys→null, and
PropLine-error→odds-api fallback all have tests.
### Files modified
- `src/utils/oddsNormalizer.js` (NFL MARKET_MAP keys)
- `tests/unit/oddsNormalizer.test.js` (NFL surface test)
- `package-lock.json` (npm audit fix)
---
## Previous Phase
SHIP BUILD v30.0 — Provider backbone: PropLine 3-key adapter, MLB Stats API, ESPN summary (Session 30)
## Session 30 (2026-06-14) — SHIPPED