Skip to content

Fix PR #56 review findings (rate limiting, auth throttling, token bootstrap, delete recovery)#57

Merged
AlexanderWagnerDev merged 1 commit into
cursor/security-review-fixesfrom
claude/pr-findings-fixes-m7b6tb
Jul 7, 2026
Merged

Fix PR #56 review findings (rate limiting, auth throttling, token bootstrap, delete recovery)#57
AlexanderWagnerDev merged 1 commit into
cursor/security-review-fixesfrom
claude/pr-findings-fixes-m7b6tb

Conversation

@AlexanderWagnerDev

@AlexanderWagnerDev AlexanderWagnerDev commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses the outstanding review findings left on #56 by chatgpt-codex-connector and coderabbitai:

  • Rate limiter LRU eviction (src/rate_limit.rs): eviction now keys on the most recent request per client bucket (entries.last()) instead of the oldest, so an actively-used bucket can't be evicted ahead of a genuinely stale one. Fixed the matching test (active_clients_are_evicted_via_lru_when_map_is_at_capacity) to give the protected bucket an unambiguously newer timestamp so it isn't flaky under HashMap iteration-order ties.
  • RTMP auth-failure rate limiting bypass (src/rtmp_bridge.rs): failures are now tracked per client IP instead of per ConnId, and the history is no longer cleared on on_close. Previously a client could reconnect (new ConnId) between failed publish/play attempts and reset the brute-force window entirely. Added a regression test (auth_rate_limit_survives_reconnect_from_same_ip).
  • Unusable token bootstrap banner (src/server.rs): the first-startup banner now prints the actual generated API token instead of a masked value — there was no other way for an operator to retrieve it. Also fixed the LRTMP2_API_TOKEN validation error message to mention the allowed '-'/'_' characters.
  • Misleading .env.example: clarified that LRTMP2_API_TOKEN is intentionally not read from the .env file by the config loader and must be set as a real process environment variable.
  • Abandoned async stream deletes (src/server.rs): if the process crashes/restarts while a 202 background delete is still draining RTMP sessions, the stream row was left enabled=0 forever. Startup now finishes any such pending deletes, since a fresh process has no surviving sessions from the prior run.

Test plan

  • cargo test --lib (66 passed)
  • cargo clippy --all-features --all-targets (clean)
  • cargo fmt --check

Generated by Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

- Rate limiter LRU eviction now keys on the most recent request per
  bucket (entries.last()) instead of the oldest, so active clients
  can't be evicted ahead of stale ones; fix the matching test to give
  the protected bucket an unambiguously newer timestamp.
- Print the freshly generated API token in the first-startup banner
  instead of the masked form, since there is no other way for an
  operator to retrieve it.
- Clarify that LRTMP2_API_TOKEN in .env.example is not read from the
  file by the config loader and must be a real process env var.
- Key RTMP auth-failure rate limiting by client IP instead of ConnId,
  and stop clearing the failure history on connection close, so
  reconnecting no longer resets the brute-force window.
- Recover streams left disabled-but-undeleted by a crash mid-delete
  (the async 202 delete path) by finishing the delete on startup.
- Fix the LRTMP2_API_TOKEN validation error message to mention the
  allowed '-'/'_' characters.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5681e7b9-6161-4ade-875e-1b82c42482fc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/pr-findings-fixes-m7b6tb

Comment @coderabbitai help to get the list of available commands.

@AlexanderWagnerDev AlexanderWagnerDev merged commit 06176b0 into cursor/security-review-fixes Jul 7, 2026
8 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06176b0bf8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/rtmp_bridge.rs
.lock()
.get(&conn)
.map(|cs| cs.remote_ip.clone())
.unwrap_or_default();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid globally bucketing pre-connect auth failures

When librtmp2 invokes a publish/play callback during server.poll() before process_server_connections has called on_connect (an ordering this file already accounts for in on_connect_preserves_prior_authorize_publish_state), this fallback uses "" as the remote IP. Failed first-poll auth attempts are then recorded under the empty key, so ten bad attempts can cause is_auth_rate_limited("") to reject unrelated clients whose first auth callback arrives before their address is recorded, while the failures are not attributed to the attacker's actual IP.

Useful? React with 👍 / 👎.

Comment thread src/rtmp_bridge.rs
let mut guard = self.auth_failures.lock();
let now = Instant::now();
let entries = guard.entry(conn).or_default();
let entries = guard.entry(remote_ip.to_string()).or_default();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bound or purge auth buckets for one-shot IPs

For an internet-exposed RTMP listener that receives failed auth attempts from many unique client IPs, each first failure inserts a new auth_failures key, but expired keys are only removed when that same IP is checked again and on_close no longer clears them. A scan or botnet can therefore grow this map indefinitely with one failed connection per address, unlike the previous per-connection state that was removed on close.

Useful? React with 👍 / 👎.

Comment thread src/server.rs
if stream.enabled {
continue;
}
match db.stream_delete(&stream.id) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not delete every disabled stream on startup

If a database contains streams intentionally stored with enabled=0 (the schema/API model exposes enabled as the stream's active/inactive state), this recovery path treats them all as abandoned async deletes and calls the cascading stream_delete, removing the stream plus dependent stats/session rows on the next server restart. Because enabled is not a dedicated pending-delete marker, startup recovery should only finalize rows known to be mid-delete rather than all inactive streams.

Useful? React with 👍 / 👎.

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