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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user