SQL injection in pgAdmin 4's named restore point endpoint (POST /browser/server/restore_point/{gid}/{sid}). The user-supplied 'value' field was interpolated directly into the SQL string with str.format() instead of being passed as a bound parameter, allowing an authenticated pgAdmin user with a connected PostgreSQL session to inject additional statements through that endpoint.
The injected SQL executes under the database role the user is already authenticated as. The defect does not cross a privilege boundary -- the user already has direct SQL access to that role through the Query Tool -- so the attacker gains no capability beyond what their database role already grants them. The marginal impact accounts for the fact that the injection path is not the documented SQL-execution interface, so a deployment that gates the Query Tool at the application layer could see SQL executed through a path it did not anticipate.
Fix passes the restore point name as a bound parameter and schema-qualifies the function call as pg_catalog.pg_create_restore_point so a non-default search_path on the connection cannot redirect the call to a shadow definition. A regression test asserts the value arrives as a bound parameter and not spliced into the SQL string.
This issue affects pgAdmin 4: from 1.0 before 9.16.
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
CVSS Score: 4.3
The attacker is an authenticated pgAdmin user with an established PostgreSQL connection. The injected SQL runs under the PostgreSQL role the user is already authenticated as, so it obtains no read access beyond what their database role already grants them through the supported Query Tool. The marginal integrity impact (I:L) acknowledges that the injection path is not the documented SQL-execution interface, so a deployment that gates the Query Tool at the application layer (for example by hiding the Query Tool UI from certain pgAdmin roles) could see SQL executed it did not anticipate, even though pgAdmin itself does not document or support such gating. Scope is unchanged: pgAdmin does not mediate a privilege boundary between the user and the database; the user supplied those credentials themselves. PoCs that use COPY TO PROGRAM or COPY FROM to read or write files on the PostgreSQL host rely on the connected role already being a PostgreSQL superuser; those operations are available to any superuser through normal SQL execution and are not capabilities granted by this defect.
Reviewer note (Dave Page, 2026-06-11): score is sound but mildly generous -- I:L for Query-Tool-gating bypass is charitable since the injection grants the attacker nothing their database role does not already permit through the supported Query Tool. A strict reading would land at I:N (2.7 LOW); 4.3 retained as the conservative-toward-higher choice.
| Attack Vector |
Network |
Scope |
Unchanged |
| Attack Complexity |
Low |
Confidentiality Impact |
None |
| Privileges Required |
Low |
Integrity Impact |
Low |
| User Interaction |
None |
Availability Impact |
None |
The attacker is an authenticated pgAdmin user with an established PostgreSQL connection. The injected SQL runs under the PostgreSQL role the user is already authenticated as, so it obtains no read access beyond what their database role already grants them through the supported Query Tool. The marginal integrity impact (I:L) acknowledges that the injection path is not the documented SQL-execution interface, so a deployment that gates the Query Tool at the application layer (for example by hiding the Query Tool UI from certain pgAdmin roles) could see SQL executed it did not anticipate, even though pgAdmin itself does not document or support such gating. Scope is unchanged: pgAdmin does not mediate a privilege boundary between the user and the database; the user supplied those credentials themselves. PoCs that use COPY TO PROGRAM or COPY FROM to read or write files on the PostgreSQL host rely on the connected role already being a PostgreSQL superuser; those operations are available to any superuser through normal SQL execution and are not capabilities granted by this defect.
Reviewer note (Dave Page, 2026-06-11): score is sound but mildly generous -- I:L for Query-Tool-gating bypass is charitable since the injection grants the attacker nothing their database role does not already permit through the supported Query Tool. A strict reading would land at I:N (2.7 LOW); 4.3 retained as the conservative-toward-higher choice.
CVSS 3.1
CVSS Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
CVSS Score: 5.3
Same reasoning as CVSS 3.1: the attacker already authenticates as the database role they would invoke through the supported Query Tool, so no new vulnerable-system or subsequent-system capability is granted. The marginal VI:L acknowledges the bypass of any application-layer Query Tool gating an operator may have set up, even though pgAdmin does not document or support such gating.
| Exploitability Metrics |
Vulnerable System Impact Metrics |
Subsequent System Impact Metrics |
| Attack Vector |
Network |
Confidentiality |
None |
Confidentiality |
None |
| Attack Complexity |
Low |
Integrity |
Low |
Integrity |
None |
| Attack Requirements |
None |
Availability |
None |
Availability |
None |
| Privileges Required |
Low |
| User Interaction |
None |
Same reasoning as CVSS 3.1: the attacker already authenticates as the database role they would invoke through the supported Query Tool, so no new vulnerable-system or subsequent-system capability is granted. The marginal VI:L acknowledges the bypass of any application-layer Query Tool gating an operator may have set up, even though pgAdmin does not document or support such gating.
CVSS 4.0