Skip to content

Prevent rapid mobile submits from duplicating chat replies#2340

Merged
glenn-sorrentino merged 1 commit into
mainfrom
agent/prevent-duplicate-chat-replies
Jul 14, 2026
Merged

Prevent rapid mobile submits from duplicating chat replies#2340
glenn-sorrentino merged 1 commit into
mainfrom
agent/prevent-duplicate-chat-replies

Conversation

@glenn-sorrentino

Copy link
Copy Markdown
Member

What changed

  • lock the conversation composer synchronously while a reply is being encrypted and posted
  • ignore overlapping submit events from taps, keyboard submission, or duplicate mobile events
  • restore the composer in a finally block so failed sends remain retryable
  • add static source/bundle coverage and update the encrypted Playwright conversation flow to dispatch two immediate submits and assert one POST

Why

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

  • browser plaintext held in the conversation composer
  • per-participant browser encryption of a conversation reply
  • authenticated JSON POST to /conversation/<public_id>/messages
  • generated static chat lifecycle bundle

No plaintext is added to requests, logs, or server storage.

Validation

  • make lint — passed
  • make test TESTS='./tests/test_frontend_compat.py ./tests/test_security_headers.py' — 66 passed
  • make test — 2,334 passed, 1 deselected, 1 expected xfail; 99% coverage
  • make audit-node-runtime — 0 vulnerabilities
  • PLAYWRIGHT_BASE_URL=http://localhost:8081 playwright test --config=playwright.e2ee.config.js tests/playwright/e2ee/client-side-encryption.spec.js — 3 passed
  • commit SSH signature verified locally

Python dependency audit

make audit-python reported Click 8.1.8 / PYSEC-2026-2132 (GHSA-47fr-3ffg-hgmw), fixed in 8.3.3. The advisory concerns command injection through click.edit(). Hush Line imports Click only for its CLI modules and does not import or call click.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

  1. Open an unlocked account conversation in a mobile browser or mobile emulation.
  2. Enter a reply and rapidly tap Send twice.
  3. Verify the composer disables immediately while sending.
  4. Verify only one encrypted request and one message bubble are created.
  5. Simulate a failed request and verify the original text remains available and the composer becomes enabled for retry.

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.

@glenn-sorrentino
glenn-sorrentino marked this pull request as ready for review July 14, 2026 04:37
@glenn-sorrentino
glenn-sorrentino merged commit dd62c8b into main Jul 14, 2026
17 checks passed
@glenn-sorrentino
glenn-sorrentino deleted the agent/prevent-duplicate-chat-replies branch July 14, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants