What happened?
Scoring uses a value the client computes and sends.
apps/frontend/src/screens/LiveQuiz.tsx:265:
const timeMs = Date.now() - questionStartTime;
apps/ws-server/src/utils/handleMessages.ts, in quiz:submit-answer:
const points = isCorrect ? Math.max(10, 1_000 - timeMs) : 0;
Anyone can send timeMs: 0 and score the maximum 1000 points on every question
regardless of how long they actually took. A negative value is not rejected
either.
There is a second, subtler problem: the server never checks that the question is
still open. A late answer — after the timer expired, or for a previous question
— is accepted and scored, as long as no row exists yet for that
(participantId, questionId).
Steps to reproduce
Suggested fix. The server already knows the deadline. timeManager.ts writes
quiz:deadline:<sessionId> to Redis, which is exactly what is needed:
- Compute elapsed time server-side from the stored deadline and the question's
timeLimit, and ignore timeMs from the payload entirely
- Reject a submission whose
questionId is not the session's current question
- Reject a submission arriving after the deadline has passed
Definition of done:
- A crafted
timeMs: 0 no longer affects the score
- An answer submitted after the timer expires scores nothing
- An answer for a non-current question is rejected
- Honest clients see no change in their scores
Worth pairing with issue 1 — same file, same handler, and both are about not
trusting the client.
Which part of Rexial?
ws-server (WebSockets), http-server (Express REST API)
How are you running Rexial?
Docker Compose (docker-compose up)
Logs or error output
Environment
No response
Before submitting
What happened?
Scoring uses a value the client computes and sends.
apps/frontend/src/screens/LiveQuiz.tsx:265:apps/ws-server/src/utils/handleMessages.ts, inquiz:submit-answer:Anyone can send
timeMs: 0and score the maximum 1000 points on every questionregardless of how long they actually took. A negative value is not rejected
either.
There is a second, subtler problem: the server never checks that the question is
still open. A late answer — after the timer expired, or for a previous question
— is accepted and scored, as long as no row exists yet for that
(participantId, questionId).Steps to reproduce
Suggested fix. The server already knows the deadline.
timeManager.tswritesquiz:deadline:<sessionId>to Redis, which is exactly what is needed:timeLimit, and ignoretimeMsfrom the payload entirelyquestionIdis not the session's current questionDefinition of done:
timeMs: 0no longer affects the scoreWorth pairing with issue 1 — same file, same handler, and both are about not
trusting the client.
Which part of Rexial?
ws-server (WebSockets), http-server (Express REST API)
How are you running Rexial?
Docker Compose (docker-compose up)
Logs or error output
Environment
No response
Before submitting