fix(analytics): bound and validate event timestamp, require object properties - #333
Merged
Merged
Conversation
…operties Closes the S7 residual from the 2026-08-04 audit re-verification: `timestamp` reached the log line with no type/length validation, and non-object `properties` slipped through the key-count/byte-size checks. Adds a 32-char cap with Date.parse sanity for timestamps and a plain-object check for properties, plus regression tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the S7 residual flagged by the 2026-09-04 remediation re-verification of the 2026-08-04 audit (#322 capped
eventandproperties, buttimestampwas missed):timestamphad no validation at all — no type check, no length cap — and is written straight into the log line. Under the 100 req/min rate limit each IP could still push ~100 MB/min of arbitrary log content via{"event":"x","timestamp":"<huge string>"}. Now: must be a string, ≤ 32 chars (ISO-8601 max is 29), and parseable byDate.parse; otherwise 400.propertiesslipped through — the existing checks only countedObject.keys()andJSON.stringify()bytes, so a short string/number payload passed and was logged as-is. Now: must be a plain object (non-null, non-array); otherwise 400.Legitimate traffic is unaffected: the client (
src/lib/analytics/index.ts) always sendsnew Date().toISOString()(24 chars) and an object (default{}).Verification
tests/unit/analytics-event-route.test.ts(oversized / non-string / unparseable timestamp rejected; valid ISO timestamp logged through; string and nullpropertiesrejected)tsc --noEmitclean; eslint 0 errors (6 pre-existing warnings in untouched files)