fix(security): add missing auth decorators to Constraints/preferences/debugger/schema_diff routes (CVE-2026-12046 follow-up)

In SERVER mode pgAdmin enforces authentication per route via
@pga_login_required; the before_request hook only handles desktop
auto-login and the Kerberos/Webserver redirect, so a route shipped
without the decorator is reachable unauthenticated (CWE-306). This is
the same defect class as CVE-2026-12046 (the sqleditor close/
update_connection routes).

A sweep found further omissions, now fixed with @pga_login_required:

* Constraints blueprint: nodes, proplist (obj), delete -- the routes
  named in the "SQL injection in pgAdmin index Statistics" follow-up
  report as an incomplete fix for CVE-2026-12046. delete is a
  state-mutating DELETE (removes table constraints); nodes/proplist
  return object information. Adds the missing pga_login_required import
  to this module.
* preferences.get_all_cli (GET)
* debugger.close (DELETE)
* schema_diff.close (DELETE)
This commit is contained in:
Dave Page
2026-07-25 00:55:46 +05:30
committed by Ashesh Vashi
parent e7a8576731
commit 24fdcf0f58
4 changed files with 7 additions and 0 deletions
@@ -19,6 +19,7 @@ from flask_babel import gettext
from pgadmin.browser.collection import CollectionNodeModule
from pgadmin.utils.ajax import make_json_response, \
make_response as ajax_response, internal_server_error
from pgadmin.user_login_check import pga_login_required
from config import PG_DEFAULT_DRIVER
from .type import ConstraintRegistry
@@ -112,6 +113,7 @@ blueprint = ConstraintsModule(__name__)
@blueprint.route('/nodes/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/')
@pga_login_required
def nodes(**kwargs):
"""
Returns all constraint as a tree node.
@@ -137,6 +139,7 @@ def nodes(**kwargs):
@blueprint.route('/obj/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/')
@pga_login_required
def proplist(**kwargs):
"""
Returns all constraint with properties.
@@ -164,6 +167,7 @@ def proplist(**kwargs):
methods=['DELETE'])
@blueprint.route('/delete/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/',
methods=['DELETE'])
@pga_login_required
def delete(**kwargs):
"""
Delete multiple constraints under the table.
+1
View File
@@ -185,6 +185,7 @@ def preferences_s():
@blueprint.route("/get_all_cli", methods=["GET"], endpoint='get_all_cli')
@pga_login_required
def get_all_cli():
"""Fetch all preferences for caching."""
# Load Preferences
+1
View File
@@ -943,6 +943,7 @@ def initialize_target(debug_type, trans_id, sid, did,
@blueprint.route(
'/close/<int:trans_id>', methods=["DELETE"], endpoint='close'
)
@pga_login_required
def close(trans_id):
"""
close(trans_id)
@@ -238,6 +238,7 @@ def initialize(trans_id):
@blueprint.route('/close/<int:trans_id>',
methods=["DELETE"],
endpoint='close')
@pga_login_required
def close(trans_id):
"""
Remove the session details for the particular transaction id.