Background
The locationPayloadSchema in validator.js validates that timestamp is a valid ISO 8601 string when provided. However, it does not validate whether the timestamp is temporally reasonable. Clients can send timestamps from hours in the past or far in the future, corrupting historical tracks and bypassing replay-detection logic.
Category: Security / Enhancement
Difficulty: Medium
Priority: Medium
Labels: security, enhancement, backend
Problem Statement
Accepting arbitrarily old or future-dated timestamps enables:
- Data poisoning — Historical track records are polluted with spurious coordinates.
- Replay attacks — A captured valid message can be replayed indefinitely since there is no freshness check.
- Analytics corruption — Dashboards and geofence calculations may act on stale positions.
Requirements
- Add a
MAX_TIMESTAMP_SKEW_MS config value (default: 30000 — 30 seconds).
- When
timestamp is present in a location_update payload, reject the message if |Date.now() - Date.parse(timestamp)| > MAX_TIMESTAMP_SKEW_MS.
- Return
{ ok: false, error: 'Timestamp is too old or too far in the future' }.
- Log validation failures with
logger.warn including clientId and the offending timestamp.
- Add
MAX_TIMESTAMP_SKEW_MS to .env.example.
- Write unit tests: timestamp within window (accepted), too old (rejected), in future (rejected), no timestamp (accepted).
Acceptance Criteria
Implementation Notes
Implement the check inside validateMessage in validator.js after the Zod schema parse:
const skew = Number(process.env.MAX_TIMESTAMP_SKEW_MS ?? 30000);
if (result.data.type === 'location_update' && result.data.payload.timestamp) {
const diff = Math.abs(Date.now() - Date.parse(result.data.payload.timestamp));
if (diff > skew) return { ok: false, error: 'Timestamp is too old or too far in the future' };
}
Use vi.spyOn(Date, 'now') in tests to control the current time.
Files Likely to Change
src/validator.js
.env.example
tests/validator.test.js
Definition of Done
Stale and future-dated location updates are rejected. The check is configurable and fully tested.
Estimated Complexity
Medium — requires careful handling of the optional timestamp field and time-dependent testing strategy.
Background
The
locationPayloadSchemainvalidator.jsvalidates thattimestampis a valid ISO 8601 string when provided. However, it does not validate whether the timestamp is temporally reasonable. Clients can send timestamps from hours in the past or far in the future, corrupting historical tracks and bypassing replay-detection logic.Category: Security / Enhancement
Difficulty: Medium
Priority: Medium
Labels: security, enhancement, backend
Problem Statement
Accepting arbitrarily old or future-dated timestamps enables:
Requirements
MAX_TIMESTAMP_SKEW_MSconfig value (default:30000— 30 seconds).timestampis present in alocation_updatepayload, reject the message if|Date.now() - Date.parse(timestamp)| > MAX_TIMESTAMP_SKEW_MS.{ ok: false, error: 'Timestamp is too old or too far in the future' }.logger.warnincludingclientIdand the offending timestamp.MAX_TIMESTAMP_SKEW_MSto.env.example.Acceptance Criteria
timestampfield are accepted normally.MAX_TIMESTAMP_SKEW_MS=0rejects all messages that include any timestamp.Implementation Notes
Implement the check inside
validateMessageinvalidator.jsafter the Zod schema parse:Use
vi.spyOn(Date, 'now')in tests to control the current time.Files Likely to Change
src/validator.js.env.exampletests/validator.test.jsDefinition of Done
Stale and future-dated location updates are rejected. The check is configurable and fully tested.
Estimated Complexity
Medium — requires careful handling of the optional timestamp field and time-dependent testing strategy.