Skip to content

Fix session and remote-input flood protection - #79

Merged
ralyodio merged 5 commits into
masterfrom
fix/remote-input-flood-protection
Aug 19, 2026
Merged

Fix session and remote-input flood protection#79
ralyodio merged 5 commits into
masterfrom
fix/remote-input-flood-protection

Conversation

@mrprecioustech

Copy link
Copy Markdown
Contributor

Summary

  • coalesce and rate-limit remote input, bound renderer/main-process queues, and suppress rejection log storms
  • add bounded API rate limits for joins, token minting, signaling, chat, and stats
  • reject oversized control packets and send stale SFU pointer/scroll samples unreliably to avoid backlog

Validation

  • targeted web and desktop unit suites
  • web and desktop typechecks
  • git diff --check

@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

66 finding(s)

HIGH/CRITICAL: 13 | MEDIUM: 35 | LOW: 18

Severity Rule Location
HIGH sh-eval-expansion .githooks/pre-commit:33
HIGH js-electron-node-integration apps/desktop/src/main/window.ts:49
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:691
HIGH sh-unquoted-expansion-destructive apps/installer/scripts/install.sh:715
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:813
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:815
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:894
HIGH sh-unquoted-expansion-destructive apps/installer/scripts/install.sh:910
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:1064
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:1066
HIGH sh-remote-script-execution apps/installer/scripts/install.sh:1128
HIGH sh-remote-script-execution apps/livekit/setup-livekit-server.sh:93
HIGH sh-remote-script-execution apps/turn/deploy-droplet.sh:62
MEDIUM insecure-temp-file .githooks/commit-msg:19
MEDIUM insecure-temp-file .githooks/post-commit:22
MEDIUM insecure-temp-file apps/installer/scripts/install.sh:370
MEDIUM insecure-temp-file apps/installer/scripts/install.sh:393
MEDIUM insecure-temp-file apps/installer/scripts/install.sh:402
MEDIUM insecure-temp-file apps/installer/scripts/install.sh:438
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:48
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:73
MEDIUM js-unescaped-html-sink apps/web/src/app/c/[handle]/page.tsx:192
MEDIUM js-unescaped-html-sink apps/web/src/app/l/[joinCode]/page.tsx:125
MEDIUM js-unescaped-html-sink apps/web/src/app/l/[joinCode]/page.tsx:219
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:142
MEDIUM js-unescaped-html-sink apps/web/src/app/live/page.tsx:145
MEDIUM js-unescaped-html-sink apps/web/src/app/page.tsx:122
MEDIUM js-unescaped-html-sink apps/web/src/app/pricing/page.tsx:284
MEDIUM js-open-redirect apps/web/src/app/pricing/UpgradeButton.tsx:50
MEDIUM js-unescaped-html-sink apps/web/src/app/u/[username]/page.tsx:282
MEDIUM redos-nested-quantifier apps/web/src/lib/deliverable.ts:11
MEDIUM manifest-install-lifecycle-script package.json:55
MEDIUM sql-template-interpolation packages/ai-core/src/prompts.ts:36
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:154
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:160
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:208
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/apt.ts:313
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/aur.ts:341
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/chocolatey.ts:264
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/chocolatey.ts:288
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/rpm.ts:201
MEDIUM js-shell-exec-interpolation scripts/lib/package-managers/rpm.ts:261
MEDIUM js-shell-exec-interpolation scripts/release.mjs:145
MEDIUM js-shell-exec-interpolation scripts/release.mjs:146
MEDIUM js-shell-exec-interpolation scripts/release.mjs:147
MEDIUM js-shell-exec-interpolation scripts/version-bump.mjs:169
MEDIUM js-shell-exec-interpolation scripts/version-bump.mjs:170
MEDIUM js-shell-exec-interpolation scripts/version-bump.mjs:171
LOW insecure-temp-file apps/desktop/src/main/streaming/index.test.ts:64
LOW secret-generic-credential apps/livekit/fly.toml:12

…and 16 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

mrprecioustech and others added 3 commits August 18, 2026 11:11
The Lint job failed on one error, which stopped Type check and Format check
from running at all — and both of those had problems waiting behind it.

getClientIp used `||` where @typescript-eslint/prefer-nullish-coalescing
wants `??`. Swapping the operator would have been a silent behaviour change:
an `x-forwarded-for` of ", 1.2.3.4" trims its first hop to an empty string,
and `??` returns that empty string rather than falling through. An empty
rate-limit key is a *different* bucket from the shared 'unknown' fallback, so
a client could double its own allowance just by prefixing a comma — in the
one file whose whole job is to stop that. The check is now explicit about
both the undefined and the empty case, which satisfies the rule and keeps the
original semantics exactly.

Covered by tests: a blank first hop from a leading comma, a whitespace-only
header and an empty header all resolve to the shared bucket, plus x-real-ip
precedence and whitespace trimming.

Format check was failing on six files that had never been run through
Prettier. Formatted, no logic touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
prune() examined a single entry and then broke out whenever the map sat
below its cap, so expired entries accumulated until the table filled up
instead of being cleaned as they aged. Once full it deleted whichever key
came first in insertion order rather than the one nearest expiry, which
could restart a throttle that still had most of its window left while an
about-to-expire entry survived.

The sweep is safe to run to completion because entries are written with one
constant window, so iteration order is ascending resetAt: the first entry
still inside its window means every entry behind it is too. That invariant
had a hole — `Map.set` on a key that already exists keeps its original
position, so a key whose window restarted stayed at the head with a new
resetAt and stopped the sweep before it reached genuinely expired keys.
check() now deletes before re-inserting so a refreshed key moves to the tail.

Cost stays amortised O(1) per call: each entry is deleted once in its life
plus at most one eviction, so this does not turn a burst of fresh keys into
a full scan per request.

Adds a `size` accessor for tests and diagnostics, and five tests. Two fail
against the previous implementation: a table of 50 expired entries only
shed one of them, and a restarted key left expired entries behind it
unreachable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ralyodio
ralyodio merged commit ede392d into master Aug 19, 2026
14 checks passed
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