Skip to content

fix(security): manual auth endpoint leaks#1340

Merged
MODSetter merged 3 commits intomainfrom
dev
May 4, 2026
Merged

fix(security): manual auth endpoint leaks#1340
MODSetter merged 3 commits intomainfrom
dev

Conversation

@MODSetter
Copy link
Copy Markdown
Owner

@MODSetter MODSetter commented May 4, 2026

Description

Motivation and Context

FIX #

Screenshots

API Changes

  • This PR includes API changes

Change Type

  • Bug fix
  • New feature
  • Performance improvement
  • Refactoring
  • Documentation
  • Dependency/Build system
  • Breaking change
  • Other (specify):

Testing Performed

  • Tested locally
  • Manual/QA verification

Checklist

  • Follows project coding standards and conventions
  • Documentation updated as needed
  • Dependencies updated as needed
  • No lint/build errors or new warnings
  • All relevant tests are passing

High-level PR Summary

This PR fixes a security vulnerability where manual authentication endpoints (email/password registration and login) were exposed even when running in Google-OAuth-only mode, allowing bots to bypass the intended AUTH_TYPE=GOOGLE restriction. The fix conditionally mounts email/password auth routers only when not in OAuth-only mode, extends the registration_allowed kill switch to cover all session-minting endpoints (including login and OAuth flows), and adds comprehensive documentation explaining that REGISTRATION_ENABLED=false acts as an emergency "freeze all new sessions" lever for incident response.

⏱️ Estimated Review Time: 30-90 minutes

💡 Review Order Suggestion
Order File Path
1 surfsense_backend/app/app.py

Need help? Join our Discord

Summary by CodeRabbit

  • Bug Fixes
    • Fixed authentication disable setting to consistently block all authentication pathways, including login and session refresh across all auth methods.
    • In Google OAuth-only deployments, unnecessary email/password authentication routes are no longer exposed.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
surf-sense-frontend Ready Ready Preview, Comment May 4, 2026 2:18am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

This PR adds conditional auth router mounting based on AUTH_TYPE configuration and expands the registration_allowed() guard to block OAuth signup/login when the global registration kill switch is disabled. Password/email auth routers are now excluded in Google-OAuth-only deployments.

Changes

Auth Flow Kill Switch & Router Conditional Mounting

Layer / File(s) Summary
Guard Contract Clarification
surfsense_backend/app/app.py (lines 598–614)
registration_allowed() docstring expanded to document its role as a master auth kill switch, explicitly naming which endpoints/flows it blocks (register, JWT login, Google OAuth authorize/callback, redirect helper).
Conditional Router Wiring
surfsense_backend/app/app.py (lines 759–797)
Password/email auth routers (/auth/jwt/*, /auth register/reset/verify) are now mounted only when config.AUTH_TYPE != "GOOGLE", preventing OAuth-only deployments from exposing non-OAuth auth surfaces.
OAuth Integration
surfsense_backend/app/app.py (lines 855–873)
registration_allowed dependency added to Google OAuth router (blocks create/login/callback) and to /auth/google/authorize-redirect endpoint, ensuring the kill switch enforces a consistent policy across all auth flows.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🐰 A hop, a skip, guards so slick,
OAuth flows and JWTs now pick,
Registration gated with a switch,
Auth routes match their niche!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(security): manual auth endpoint leaks' directly addresses the main change - preventing auth endpoints from leaking in Google-OAuth-only deployments by controlling router mounting based on AUTH_TYPE and adding kill switch dependencies.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@surfsense_backend/app/app.py`:
- Around line 597-614: The registration_allowed() kill-switch currently doesn't
block refresh-token rotation because auth_router is mounted unconditionally and
the /auth/jwt/refresh handler in refresh_access_token can still mint sessions;
fix this by gating refresh-token rotation: either move the refresh route out of
auth_router so it is only mounted when registration_allowed() is True, or add an
explicit registration_allowed() check at the start of refresh_access_token (and
return the same “registration disabled” response) while leaving revoke/logout
handlers untouched; update references where auth_router is mounted to ensure
/auth/jwt/refresh is protected (also check the other mounting sites noted around
the auth_router usage).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f0ab8c64-f751-4b7e-a40d-6c3fba5f1184

📥 Commits

Reviewing files that changed from the base of the PR and between 3b84cf8 and 2e1b9b5.

📒 Files selected for processing (1)
  • surfsense_backend/app/app.py

Comment on lines 597 to +614
def registration_allowed():
"""Master auth kill switch keyed on the REGISTRATION_ENABLED env var.

Despite the name, this dependency does NOT only gate registration. When
REGISTRATION_ENABLED is FALSE it intentionally blocks every auth surface
that could mint or refresh a session for an attacker:

* email/password ``POST /auth/register``
* email/password ``POST /auth/jwt/login``
* the Google OAuth router (``/auth/google/authorize`` and the shared
``/auth/google/callback`` handles both new signups and login for
existing users, so flipping this off locks both)
* the bespoke ``/auth/google/authorize-redirect`` helper used by the UI

Use it as a temporary "freeze all new sessions" lever during incident
response. It is not a way to disable signup while keeping login working;
for that, override ``UserManager.oauth_callback`` instead.
"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The kill switch still leaves refresh-token session minting open.

registration_allowed() is now documented and wired as a “freeze all new sessions” control, but Lines 804-805 still mount auth_router unconditionally. In surfsense_backend/app/routes/auth_routes.py:23-56, /auth/jwt/refresh can still rotate a valid refresh token into a fresh access/refresh pair without this dependency. That means an attacker holding a stolen refresh token can keep minting sessions even after REGISTRATION_ENABLED is turned off.

Please gate the refresh route too, either by splitting it out from auth_router or by enforcing the check inside refresh_access_token while leaving revoke/logout available.

Also applies to: 759-794, 855-859

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@surfsense_backend/app/app.py` around lines 597 - 614, The
registration_allowed() kill-switch currently doesn't block refresh-token
rotation because auth_router is mounted unconditionally and the
/auth/jwt/refresh handler in refresh_access_token can still mint sessions; fix
this by gating refresh-token rotation: either move the refresh route out of
auth_router so it is only mounted when registration_allowed() is True, or add an
explicit registration_allowed() check at the start of refresh_access_token (and
return the same “registration disabled” response) while leaving revoke/logout
handlers untouched; update references where auth_router is mounted to ensure
/auth/jwt/refresh is protected (also check the other mounting sites noted around
the auth_router usage).

@MODSetter MODSetter merged commit 635866a into main May 4, 2026
6 of 12 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.

1 participant