|
|
|
|
@@ -126,3 +126,40 @@ The AMMC archive and multi-platform binaries dominate repository and deployment
|
|
|
|
|
4. Add request limits, rate limiting, import schema validation, and CSP.
|
|
|
|
|
5. Add AMMC checksum verification and platform-specific release packaging.
|
|
|
|
|
6. Profile a simulated 12-car race and an endurance dataset before deeper leaderboard optimization.
|
|
|
|
|
|
|
|
|
|
## Follow-up review — 2026-09-12
|
|
|
|
|
|
|
|
|
|
Requested by the user: re-check dependencies and everything added to `server.js`/the module tree since the 2026-08-28 audit above (a long session's worth of features: track layouts, race day scheduling, staggered starts, driver transponder-conflict warnings, Settings/Event Manager/Guide tab restructurings, the video-guide and screenshot capture tooling, and several new backend routes). This is a source-level re-check, not a new penetration test.
|
|
|
|
|
|
|
|
|
|
### Verification baseline
|
|
|
|
|
|
|
|
|
|
- `npm audit` and `npm audit --omit=dev`: **0 known vulnerabilities**, both re-run 2026-09-12 (3 direct production dependencies: `better-sqlite3`, `express`, `qrcode`; ~200 packages in the full production tree).
|
|
|
|
|
- `npm test`: 205 tests passing; `npm run test:browser`: 37 scenarios passing.
|
|
|
|
|
- Node runtime observed: v22.23.2 (within the `>=22 <27` engines range).
|
|
|
|
|
- Checked every `db.prepare()`/`db.exec()` call in `server.js` (12 total) for injection risk: all parameterized (`?` placeholders); the one call that builds SQL with a template literal (`/api/passings/purge`'s dynamic `IN (...)` clause) only interpolates a computed number of `?` placeholders, never request data itself - the actual values are still bound via `.run(...sessionIds)`.
|
|
|
|
|
- Checked every `spawn()`/`execFileSync()` call reachable from the server (in `server.js`, `scripts/serverctl.js`, and the two new dev-only tooling scripts) for shell-injection risk: all use array-form arguments with no `shell: true` and no string-interpolated shell commands, so none are exploitable via shell metacharacters in a config value or filename.
|
|
|
|
|
- Re-confirmed the CORS/security-header middleware from the 2026-08-28 audit (`X-Content-Type-Options`, `Referrer-Policy`, origin allowlist via `RC_ALLOWED_ORIGINS`) is registered before every route added since, including the new ones below - no regression.
|
|
|
|
|
|
|
|
|
|
### New finding - High: `POST /api/update/run` is an unauthenticated remote restart/update trigger
|
|
|
|
|
|
|
|
|
|
Added since the last audit (the in-app update checker, ROADMAP.md "In-app update checker and one-click updater"). This inherits the existing "Critical: administration API has no authentication" finding above, but is worth calling out on its own: unlike most other unauthenticated endpoints, which expose or mutate *data*, this one is a direct **disruption primitive**. Any client that can reach the server -
|
|
|
|
|
|
|
|
|
|
- **unconditionally stops the running server first**, before checking whether an update is even available or possible (`scripts/serverctl.js`'s `update()` calls `stop()` immediately) - so a bare `POST /api/update/run` with no real update pending still causes a guaranteed brief outage, repeatable at will (no rate limiting exists anywhere in the app - see the pre-existing "Medium: large request bodies and no rate limiting" finding above);
|
|
|
|
|
- then runs `git pull --ff-only` and, if that succeeds, `npm install` against whatever the configured git remote/npm registry currently serve, before restarting.
|
|
|
|
|
|
|
|
|
|
The `--ff-only` pull and graceful fallback-to-restart-on-failure (confirmed by reading `scripts/serverctl.js`) mean this cannot rewrite git history or corrupt the working tree, and a failed pull still leaves the server running on its current code - so this is not an arbitrary-code-execution vector by itself. But on a shared trackside LAN, an unauthenticated repeated-restart trigger during a live event is a real, easy-to-trigger denial of service, more severe in practice than most of the "no auth" list above because it requires no knowledge of the app's data model to abuse - just knowing the URL.
|
|
|
|
|
|
|
|
|
|
Same LAN-only deployment mitigation as the existing "Critical" finding applies today (do not expose port 8081 to the public internet); no code change made as part of this review. Worth prioritizing ahead of the rest of the deferred auth work if a minimal interim gate (e.g. restricting this one route to loopback requests, or requiring a simple shared-secret header) is wanted before the full permissions system is designed - see ROADMAP.md, "Permissions and mobile Race Control."
|
|
|
|
|
|
|
|
|
|
### New routes since 2026-08-28, otherwise covered by existing findings
|
|
|
|
|
|
|
|
|
|
No other new route introduces a new class of risk; each falls under a finding already listed above:
|
|
|
|
|
|
|
|
|
|
- `GET /api/update-status` - read-only, same "no auth" umbrella as the rest of `/api/*`.
|
|
|
|
|
- `GET /api/network/public-address` - calls a fixed, hardcoded external URL (`api.ipify.org`) server-side with a 5s timeout; not user-controlled, so no SSRF risk. Same "no auth" umbrella (anyone can trigger an outbound request, but only ever to that one fixed address).
|
|
|
|
|
- `POST /api/passings/purge` - mutating, parameterized SQL (see above), same "no auth" umbrella.
|
|
|
|
|
- `POST /public-training/api/:shareToken/even-laps`, `.../step-training`, `.../exercise-sessions` - each still validated against the existing per-token authorization model documented in the 2026-08-28 audit's scope (shareToken lookup, 404 on invalid/disabled/unknown) and each read-modify-writes only its own slice of `state.training` server-side (`server/public_training_profile.js`) rather than accepting a client's full state blob, the same scoped-write pattern the original audit already treated as a mitigating factor for the mobile self-service surface.
|
|
|
|
|
|
|
|
|
|
### New dev-only tooling - no production exposure
|
|
|
|
|
|
|
|
|
|
`scripts/record-video-guides.mjs` and `scripts/capture-screenshots.mjs` (this session's video-guide/screenshot generators) are not imported by `server.js` or any `src/*.js` module, are never started by any HTTP route, and are meant to be run manually by a developer against an isolated temp server/SQLite instance - they have no network-reachable attack surface and were excluded from further review on that basis beyond the injection-safety check above.
|
|
|
|
|
|