Prevent rapid mobile submits from duplicating chat replies#2340
Merged
Conversation
glenn-sorrentino
marked this pull request as ready for review
July 14, 2026 04:37
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.
What changed
finallyblock so failed sends remain retryableWhy
The reply handler did not track an in-flight submission. Mobile encryption and network latency left a window where a second submit captured the same plaintext and created another encrypted message. The API correctly treated both POSTs as independent messages, so the thread showed duplicate replies.
User impact
Rapid mobile submissions now produce one encrypted reply. The composer is temporarily disabled during encryption and sending, then restored after success or failure.
Threat and risk summary
This is a behavior-preserving client-side concurrency guard. It does not alter E2EE algorithms, key material, ciphertext envelopes, authentication, CSRF validation, server persistence, notification contents, or CSP. Preventing duplicate sends reduces unintended disclosure repetition and duplicate recipient notifications.
Residual risk: the guard is scoped to one browser tab. It does not introduce server-side idempotency across tabs or hypothetical transport retries; the current client does not automatically retry message POSTs.
Affected data paths
/conversation/<public_id>/messagesNo plaintext is added to requests, logs, or server storage.
Validation
make lint— passedmake test TESTS='./tests/test_frontend_compat.py ./tests/test_security_headers.py'— 66 passedmake test— 2,334 passed, 1 deselected, 1 expected xfail; 99% coveragemake audit-node-runtime— 0 vulnerabilitiesPLAYWRIGHT_BASE_URL=http://localhost:8081 playwright test --config=playwright.e2ee.config.js tests/playwright/e2ee/client-side-encryption.spec.js— 3 passedPython dependency audit
make audit-pythonreported Click 8.1.8 /PYSEC-2026-2132(GHSA-47fr-3ffg-hgmw), fixed in 8.3.3. The advisory concerns command injection throughclick.edit(). Hush Line imports Click only for its CLI modules and does not import or callclick.edit(), so the vulnerable API is not reachable in this change or the web message path.Residual risk is the vulnerable transitive version remaining in the CLI dependency graph. Follow-up: update Click in a focused dependency PR after compatibility review. The Dependency Security Audit workflow must pass or maintainers must formally accept the documented non-reachability before merge.
Manual testing steps
The automated Playwright flow performs the back-to-back submit and single-request assertion. A separate physical-device check was not performed.
Documentation
Not updated: this fixes duplicate execution within the existing conversation workflow and does not change documented E2EE behavior or product capabilities.