Public Edit WebSocket stays open after 301 empty frames #223

Open
opened 2026-09-27 09:00:08 +00:00 by kayg · 8 comments
Owner

An adversarial run after merging dev for Forgejo #176 found that a public Edit collaboration WebSocket stayed open after the 301st empty binary frame. The probe sends 301 frames and waits up to 10 seconds for the socket to close. It reported: the 301st frame did not close the socket.

The run overlapped other worktree builds and API probes on the shared host. This may be delayed enforcement under load, so it needs an isolated rerun before changing behavior. The WebSocket opened successfully; the probe did not report a server crash or data corruption.

Probe: tests/adversarial/attack2.py, public share options section. Please confirm that empty frames consume the public collaboration per-link/IP frame budget and that the connection closes at the intended limit. Add a regression probe if this reproduces.

An adversarial run after merging `dev` for Forgejo #176 found that a public Edit collaboration WebSocket stayed open after the 301st empty binary frame. The probe sends 301 frames and waits up to 10 seconds for the socket to close. It reported: `the 301st frame did not close the socket`. The run overlapped other worktree builds and API probes on the shared host. This may be delayed enforcement under load, so it needs an isolated rerun before changing behavior. The WebSocket opened successfully; the probe did not report a server crash or data corruption. Probe: `tests/adversarial/attack2.py`, public share options section. Please confirm that empty frames consume the public collaboration per-link/IP frame budget and that the connection closes at the intended limit. Add a regression probe if this reproduces.
Author
Owner

Reproduced on the post-merge job/menu-icons server at cdc09b1d during the one full adversarial round (target/tmp/menu-icons-adversarial-latest.log, 2026-09-27): the public-edit WebSocket upgraded with 101, accepted 301 empty binary frames, and remained open for the probe's 10-second close window. The probe closed it manually afterward. This is the public collab frame rate limit check in tests/adversarial/attack2.py; the 301st frame still does not close the socket. Other public-edit session rate checks continue after it. Please include this run in the existing #223 investigation.

Reproduced on the post-merge `job/menu-icons` server at `cdc09b1d` during the one full adversarial round (`target/tmp/menu-icons-adversarial-latest.log`, 2026-09-27): the public-edit WebSocket upgraded with 101, accepted 301 empty binary frames, and remained open for the probe's 10-second close window. The probe closed it manually afterward. This is the `public collab frame rate limit` check in `tests/adversarial/attack2.py`; the 301st frame still does not close the socket. Other public-edit session rate checks continue after it. Please include this run in the existing #223 investigation.
Author
Owner

The latest post-merge real-server adversarial round reproduced this: after sending 301 empty binary frames on an authorized public Edit WebSocket, the probe did not observe closure within 10 seconds. The same host had several concurrent build and adversarial jobs. The server stayed alive. The frame counter in session.rs is 300 per minute; an isolated check is still needed to rule out minute-boundary timing.

The latest post-merge real-server adversarial round reproduced this: after sending 301 empty binary frames on an authorized public Edit WebSocket, the probe did not observe closure within 10 seconds. The same host had several concurrent build and adversarial jobs. The server stayed alive. The frame counter in `session.rs` is 300 per minute; an isolated check is still needed to rule out minute-boundary timing.
Author
Owner

Post-merge adversarial run at c2ff7b40 again found that a public Edit WebSocket stayed open after the 301st empty binary frame; the probe waited 10 seconds for closure. Multiple other worktrees were active on the shared host. The API server was alive at the end. Please replay on an isolated host before changing the frame budget.

Post-merge adversarial run at c2ff7b40 again found that a public Edit WebSocket stayed open after the 301st empty binary frame; the probe waited 10 seconds for closure. Multiple other worktrees were active on the shared host. The API server was alive at the end. Please replay on an isolated host before changing the frame budget.
Author
Owner

Repeat evidence from the required post-merge adversarial round for #219: at merge head 3025699104e0b57ec2275edd5fee00b5374f3d9d, the public collaboration probe sent 301 empty frames on an authenticated Public Edit WebSocket. The socket did not close within the probe's 10-second bound (FINDING public collab frame rate limit: the 301st frame did not close the socket). The server remained alive at the end of the round. This matches the open finding tracked here; no collaboration or API code changed in #219.

Repeat evidence from the required post-merge adversarial round for #219: at merge head `3025699104e0b57ec2275edd5fee00b5374f3d9d`, the public collaboration probe sent 301 empty frames on an authenticated Public Edit WebSocket. The socket did not close within the probe's 10-second bound (`FINDING public collab frame rate limit: the 301st frame did not close the socket`). The server remained alive at the end of the round. This matches the open finding tracked here; no collaboration or API code changed in #219.
Author
Owner

The same check reproduced on job/fonts after merging dev (ac941215): an anonymous public Edit WebSocket accepted 301 empty binary frames and did not close within the probe's 10-second wait. The full run later reported server alive at end: True, with no crash.

This round also overlapped other build and browser jobs on the shared host. It confirms the finding under load, but does not replace the isolated rerun requested here.

The same check reproduced on `job/fonts` after merging `dev` (`ac941215`): an anonymous public Edit WebSocket accepted 301 empty binary frames and did not close within the probe's 10-second wait. The full run later reported `server alive at end: True`, with no crash. This round also overlapped other build and browser jobs on the shared host. It confirms the finding under load, but does not replace the isolated rerun requested here.
Author
Owner

Duplicate of #270: both report the public-edit WebSocket staying open after 301 empty binary frames, with the 300-frame per-link/IP limit and a 10-second close check. #270 also records the expected guest-presence cleanup. Recommend keeping #270 as the tracking issue and linking this run as repeated evidence.

Duplicate of #270: both report the public-edit WebSocket staying open after 301 empty binary frames, with the 300-frame per-link/IP limit and a 10-second close check. #270 also records the expected guest-presence cleanup. Recommend keeping #270 as the tracking issue and linking this run as repeated evidence.
Author
Owner

Duplicate of #270: both report a public-edit WebSocket staying open after the frame limit. Keep #270 as the active tracker.

Duplicate of #270: both report a public-edit WebSocket staying open after the frame limit. Keep #270 as the active tracker.
kayg closed this issue 2026-10-03 11:55:50 +00:00
Author
Owner

Correction to the issue-hygiene disposition: this issue carries an explicit OPEN marker, so it must remain open under the sweep rules. The earlier duplicate disposition was too aggressive. Reopening and leaving it for the owner to reclassify.

Correction to the issue-hygiene disposition: this issue carries an explicit OPEN marker, so it must remain open under the sweep rules. The earlier duplicate disposition was too aggressive. Reopening and leaving it for the owner to reclassify.
kayg reopened this issue 2026-10-03 12:14:22 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#223
No description provided.