Skip to content

Conversation

@samuelwei
Copy link
Collaborator

@samuelwei samuelwei commented Oct 9, 2025

Type

  • Bugfix
  • Feature
  • Documentation
  • Refactoring (e.g. Style updates, Test implementation, etc.)
  • Other (please describe)

Checklist

  • Code updated to current develop branch head
  • Passes CI checks
  • Is a part of an issue
  • Tests added for the bugfix or newly implemented feature, describe below why if not
  • Changelog is updated
  • Documentation of code and features exists

Changes

  • Add rate limiting to room API endpoints to mitigate room ID enumeration attacks

Other information

All API requests resulting in a 404 response due to an invalid room ID are counted. If the limit exceeds the threshold all room api calls are blocked.

Summary by CodeRabbit

  • New Features

    • Rate limiting added for room-related endpoints: only counts requests that return 404, limited to 10 requests/minute per user/IP; many room management, membership, files, recordings, tokens, and streaming routes are now throttled.
  • Documentation

    • Changelog updated with an Unreleased entry referencing the new rate-limiting change.
  • Tests

    • Added tests validating 404-based rate limiting for guests and authenticated users, related routes, per-user behavior, and limit reset timing.

@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

Walkthrough

Adds a "room-enumeration" rate limiter that counts only 404 responses for room-bound routes, applies that throttle to many room-related API endpoints, updates the changelog with the PR, and adds a feature test verifying per-user/IP 404 rate limiting and reset behavior.

Changes

Cohort / File(s) Summary
Changelog update
CHANGELOG.md
Added Unreleased entry for "Rate limiting to prevent Room-ID enumeration attacks" and referenced PR [#2518].
Rate limiter configuration
app/Providers/RouteServiceProvider.php
Added room-enumeration limiter (10 requests/min per user or IP) that only increments when the response is 404 and the room route param does not resolve to a Room; added Room and Response imports.
Routing — room throttling and reorganization
routes/api.php
Wrapped a wide set of room-related endpoints in throttle:room-enumeration, reorganized route groups (added/adjusted can:*, scopeBindings, room auth middleware), and moved many room CRUD, membership, files, recordings, streaming, tokens, meetings, start/join/settings, and related OPTIONS into the throttled scope.
Tests — feature coverage
tests/Backend/Feature/api/v1/Room/RoomTest.php
Added test_room_404_rate_limit() to validate 404-only counting for guests and authenticated users, per-user/IP scoping, related-route coverage (e.g., rooms.show and files.show), and time-based reset behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • danielmachill

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Security: Prevent room ID enumeration" directly and concisely describes the primary objective of the changeset. The changes add rate limiting specifically to prevent room ID enumeration attacks, as evidenced by the new 'room-enumeration' rate limiter in RouteServiceProvider, the throttled route groups in routes/api.php, and the test coverage validating this behavior. The title is clear, specific, and appropriately categorized with the "Security:" prefix, allowing teammates to quickly understand the main purpose of the change.
Description Check ✅ Passed The PR description follows the template structure with all major sections present: Type is clearly identified as "Feature," the Checklist includes appropriate items marked as completed (code updated, CI passes, tests added, changelog updated), Changes section provides a concise summary of the rate limiting implementation, and Other information explains the behavior. While the "Fixes #" section is empty and two checklist items are unchecked ("Is a part of an issue" and "Documentation of code and features exists"), these appear non-critical as the template acknowledges that not all points are always applicable. The description is substantially complete and conveys the PR's purpose clearly.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sec-prevent-room-enumeration

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fdd79b8 and e804e32.

📒 Files selected for processing (1)
  • CHANGELOG.md (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Backend
  • GitHub Check: Docker Build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@samuelwei
Copy link
Collaborator Author

samuelwei commented Oct 9, 2025

TODO

  • Add tests
  • Add log entries

@codecov
Copy link

codecov bot commented Oct 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.66%. Comparing base (bc9287a) to head (e804e32).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #2518      +/-   ##
=============================================
+ Coverage      96.03%   96.66%   +0.63%     
- Complexity      1647     1649       +2     
=============================================
  Files            249      426     +177     
  Lines           5747    11999    +6252     
  Branches           0     2063    +2063     
=============================================
+ Hits            5519    11599    +6080     
- Misses           228      400     +172     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cypress
Copy link

cypress bot commented Oct 9, 2025

PILOS    Run #2652

Run Properties:  status check passed Passed #2652  •  git commit e804e32e36: Security: Prevent room ID enumeration
Project PILOS
Branch Review sec-prevent-room-enumeration
Run status status check passed Passed #2652
Run duration 07m 27s
Commit git commit e804e32e36: Security: Prevent room ID enumeration
Committer Samuel Weirich
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 599
View all changes introduced in this branch ↗︎

@samuelwei samuelwei force-pushed the sec-prevent-room-enumeration branch from 2d96ac3 to 61c5d8e Compare October 10, 2025 10:07
@samuelwei samuelwei marked this pull request as ready for review October 10, 2025 10:11
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
app/Providers/RouteServiceProvider.php (1)

76-89: Limiter design is sound; make limits configurable and verify 'after' semantics

  • Counts only 404s when the room param didn’t bind to a Room model. Good approach to avoid false positives.
  • Suggest reading limits from config (e.g., perMinutes/attempts), not hard-coded 10/min.

Proposed change:

-        RateLimiter::for('room-enumeration', function (Request $request) {
-            return Limit::perMinute(10)
+        RateLimiter::for('room-enumeration', function (Request $request) {
+            $max = config('rate_limits.room_enumeration.max_attempts', 10);
+            $decay = config('rate_limits.room_enumeration.decay_minutes', 1);
+            return Limit::perMinutes($decay, $max)
                 ->by($request->user()?->id ?: $request->ip())
                 ->after(function (\Symfony\Component\HttpFoundation\Response $response) use ($request) {
                     // If the response is not a 404, do not count this request
                     if ($response->getStatusCode() !== 404) {
                         return false;
                     }
 
                     // Only count the request if the route parameter 'room' was not resolved to a Room model
                     // Prevent counting requests that are valid and return a 404 for other reasons
                     return ! ($request->route('room') instanceof Room);
                 });
         });

Please confirm the project’s Laravel version supports Limit::after with a boolean return to control counting. If not, we’ll switch to an alternative (e.g., custom middleware with RateLimiter::hit only on 404). Based on learnings

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b3ff518 and 61c5d8e.

📒 Files selected for processing (4)
  • CHANGELOG.md (2 hunks)
  • app/Providers/RouteServiceProvider.php (2 hunks)
  • routes/api.php (2 hunks)
  • tests/Backend/Feature/api/v1/Room/RoomTest.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/Providers/RouteServiceProvider.php (2)
app/Models/User.php (1)
  • User (20-349)
_ide_helper.php (2)
  • for (9551-9555)
  • ip (10222-10226)
tests/Backend/Feature/api/v1/Room/RoomTest.php (1)
app/Models/Room.php (2)
  • Room (19-464)
  • owner (214-217)
routes/api.php (7)
app/Http/Controllers/api/v1/RoomController.php (1)
  • RoomController (32-426)
app/Http/Controllers/api/v1/RoomMemberController.php (1)
  • RoomMemberController (20-215)
app/Http/Controllers/api/v1/RecordingController.php (1)
  • RecordingController (16-103)
app/Http/Controllers/api/v1/RoomStreamingController.php (1)
  • RoomStreamingController (16-135)
app/Http/Controllers/api/v1/RoomTokenController.php (1)
  • RoomTokenController (17-139)
app/Http/Controllers/api/v1/RoomFileController.php (1)
  • RoomFileController (16-163)
app/Http/Controllers/api/v1/RecordingFormatController.php (1)
  • RecordingFormatController (10-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Docker Build
🔇 Additional comments (6)
CHANGELOG.md (2)

13-13: Changelog entry LGTM

Accurately reflects the new security feature.


561-561: Reference link added correctly

Footnote for [#2518] is consistent and valid.

tests/Backend/Feature/api/v1/Room/RoomTest.php (1)

419-470: Strong coverage for 404-based throttling

Covers guest vs auth, cross-route blocking, window reset, and excluding valid-room 404s. Nicely done.

routes/api.php (3)

77-137: Throttle scope alignment looks good; confirm intent to block writes after threshold

Wrapping all per-room endpoints means once the 404 threshold is exceeded, even valid writes (update/delete, streaming actions, membership ops, etc.) are blocked for the window. This matches the PR note (“all room API calls are blocked”). If that’s intended, LGTM.


164-165: Meetings endpoint throttled consistently

Brings meetings under the same limiter. Consistent with the threat model.


171-187: Public room routes throttled with auth middleware where needed

Good use of room.authenticate and scopeBindings alongside the throttle to keep behavior consistent for guests and users.

@samuelwei samuelwei force-pushed the develop branch 2 times, most recently from 88ee280 to bc9287a Compare October 20, 2025 15:17
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