Backend security: socket.io 2.5.1, ws, koa, qs, linkify-it; bound socket buffer #20

Merged
backmeupplz merged 1 commit from security/backend-deps into main 2026-10-23 00:41:34 +00:00
Owner

Security update for the public backend (backend.todorant.com, ws.todorant.com). Every runtime advisory in the socket/ws/koa/qs/linkify stack is now cleared in osv-scanner. The only ws advisory left is in jest's jsdom (dev-only; production installs with --production).

Changes (backend/)

  • socket.io 2.3.0 → 2.5.1. It stays on protocol v2, so existing v1 (socket.io) clients keep working. This pulls engine.io 3.6.2, socket.io-parser 3.4.5 / 3.3.6 (CVE-2022-2421 type confusion, attachment validation) and ws 7.5.13. I dropped the two stale socket.io-parser lockfile entries so yarn would re-resolve them inside the same ranges; there is no permanent resolution.
  • ws (direct dependency, used by /v2/ws realtime sync) 7.5.10 → 7.5.13: CVE-2026-48779, memory exhaustion from tiny fragments.
  • koa 2.13.0 → 2.16.4: GHSA-593f-38f6-jp5m (X-Forwarded-Host/Proto ReDoS, reachable because app.proxy = true) and GHSA-7gcc-r8m5-44qm.
  • qs resolution ^6.14.1 (a single 6.16.1): CVE-2022-24999 and the later qs DoS fixes, reached through koa-bodyparser → co-body.
  • linkify-it 3.0.2 → 5.0.2: GHSA-22p9-wv53-3rq4 and GHSA-v245-v573-v5vm, quadratic match/mailto: scans on every todo text. The 5.x CJS build keeps require('linkify-it') returning the factory. The #tag schema, URLs and mailto match exactly as before (checked with Latin and Cyrillic tags).
  • maxHttpBufferSize 9e10 → 5e7 in src/sockets/io.ts. At 9e10, any client, before authorizing, could make the server buffer ~90 GB per message. engine.io's own default is 1 MB. 50 MB leaves plenty of room for v1 sync pushes. The 9e10 dates to the 2022 initial commit with no rationale, most likely set when engine.io 3.6 lowered its default.

Testing

I replicated backend.yml locally against MongoDB 8.0 (what prod runs now) on Node 22, on both main and this branch:

check main branch
prettier --check ✅ ✅
eslint --max-warnings 0 ✅ ✅
tsc --noEmit ✅ ✅
jest v2.ts + appleAuthKey.ts (CI set) 21/21 21/21
full jest suite 78/80 78/80 (same 2 pre-existing failures: docs md endpoint, delegate TelegramLoginPayload)

Real v1 client test (socket.io-client 2.5.0 against the built server):

  • anonymous login → authorize over socket.io → authorized ✅ on both
  • ~1 MB push: connection stays up ✅ on both
  • 60 MB push: main accepts it (websocket and polling); this branch drops the socket (websocket after 0.8 s, polling after 4 s) and the server keeps running ✅

⚠️ Deploy note

Easypanel builds deploy/backend. That branch was promoted by .github/workflows/backend.yml with gh api … git/refs/heads/deploy/backend (GitHub API). Since the move to Forgejo, no workflow has run for this repo on Forgejo, and that step can't promote Forgejo's branch anyway. So merging this won't deploy on its own until the promotion is ported to Forgejo Actions, or deploy/backend is fast-forwarded to main on Forgejo.

🤖 Generated with Claude Code

Security update for the public backend (backend.todorant.com, ws.todorant.com). Every runtime advisory in the socket/ws/koa/qs/linkify stack is now cleared in osv-scanner. The only ws advisory left is in jest's jsdom (dev-only; production installs with `--production`). ## Changes (backend/) - **socket.io** 2.3.0 → 2.5.1. It stays on protocol v2, so existing v1 (socket.io) clients keep working. This pulls engine.io 3.6.2, socket.io-parser 3.4.5 / 3.3.6 (CVE-2022-2421 type confusion, attachment validation) and ws 7.5.13. I dropped the two stale socket.io-parser lockfile entries so yarn would re-resolve them inside the same ranges; there is no permanent resolution. - **ws** (direct dependency, used by `/v2/ws` realtime sync) 7.5.10 → 7.5.13: CVE-2026-48779, memory exhaustion from tiny fragments. - **koa** 2.13.0 → 2.16.4: GHSA-593f-38f6-jp5m (X-Forwarded-Host/Proto ReDoS, reachable because `app.proxy = true`) and GHSA-7gcc-r8m5-44qm. - **qs** resolution `^6.14.1` (a single 6.16.1): CVE-2022-24999 and the later qs DoS fixes, reached through koa-bodyparser → co-body. - **linkify-it** 3.0.2 → 5.0.2: GHSA-22p9-wv53-3rq4 and GHSA-v245-v573-v5vm, quadratic `match`/`mailto:` scans on every todo text. The 5.x CJS build keeps `require('linkify-it')` returning the factory. The `#tag` schema, URLs and mailto match exactly as before (checked with Latin and Cyrillic tags). - **maxHttpBufferSize** 9e10 → 5e7 in `src/sockets/io.ts`. At 9e10, any client, before authorizing, could make the server buffer ~90 GB per message. engine.io's own default is 1 MB. 50 MB leaves plenty of room for v1 sync pushes. The 9e10 dates to the 2022 initial commit with no rationale, most likely set when engine.io 3.6 lowered its default. ## Testing I replicated `backend.yml` locally against MongoDB 8.0 (what prod runs now) on Node 22, on both `main` and this branch: | check | main | branch | |---|---|---| | prettier --check | ✅ | ✅ | | eslint --max-warnings 0 | ✅ | ✅ | | tsc --noEmit | ✅ | ✅ | | jest v2.ts + appleAuthKey.ts (CI set) | 21/21 | 21/21 | | full jest suite | 78/80 | 78/80 (same 2 pre-existing failures: docs md endpoint, delegate TelegramLoginPayload) | Real v1 client test (socket.io-client 2.5.0 against the built server): - anonymous login → `authorize` over socket.io → `authorized` ✅ on both - ~1 MB push: connection stays up ✅ on both - 60 MB push: **main accepts it** (websocket and polling); **this branch drops the socket** (websocket after 0.8 s, polling after 4 s) and the server keeps running ✅ ## ⚠️ Deploy note Easypanel builds `deploy/backend`. That branch was promoted by `.github/workflows/backend.yml` with `gh api … git/refs/heads/deploy/backend` (GitHub API). Since the move to Forgejo, no workflow has run for this repo on Forgejo, and that step can't promote Forgejo's branch anyway. So merging this won't deploy on its own until the promotion is ported to Forgejo Actions, or `deploy/backend` is fast-forwarded to `main` on Forgejo. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Backend: patch socket.io/ws/koa/qs/linkify-it advisories, bound socket buffer
Some checks failed
Backend / check (pull_request) Failing after 9m10s
Backend / deploy (pull_request) Has been skipped
befa138203
- socket.io 2.3.0 -> 2.5.1 (still protocol v2 for the v1 apps): engine.io 3.6.2,
  socket.io-parser 3.4.5/3.3.6 (CVE-2022-2421 + attachment validation), ws 7.5.13
- direct ws 7.5.10 -> 7.5.13 for /v2/ws (CVE-2026-48779 memory exhaustion)
- koa 2.13.0 -> 2.16.4 (X-Forwarded-* ReDoS and GHSA-7gcc; app.proxy is on)
- qs resolution ^6.14.1 -> 6.16.1 (CVE-2022-24999 and later DoS fixes)
- linkify-it 3.0.2 -> 5.0.2 (quadratic match/mailto DoS)
- maxHttpBufferSize 9e10 -> 5e7: a client could make the server buffer ~90 GB

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI: reach the mongo service by name on Forgejo
All checks were successful
Backend / check (pull_request) Successful in 3m10s
Backend / deploy (pull_request) Has been skipped
f60a7a278b
Forgejo Actions runs the job in a container on a shared network with the
service, so localhost:27017 is the job container itself (ECONNREFUSED, every
v2 test timed out). GitHub Actions no longer runs for this repo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
backmeupplz force-pushed security/backend-deps from f60a7a278b
All checks were successful
Backend / check (pull_request) Successful in 3m10s
Backend / deploy (pull_request) Has been skipped
to efd6a7abf1
Some checks failed
Backend / check (pull_request) Failing after 1m57s
Backend / deploy (pull_request) Has been skipped
Android / check (pull_request) Successful in 3m22s
2026-10-22 23:58:29 +00:00
Compare
backmeupplz deleted branch security/backend-deps 2026-10-23 00:41:37 +00:00
Sign in to join this conversation.
No description provided.