Repository navigation
feat: add definer_function_uses_current_user lint (0034) - #201
Open
mattmuller wants to merge 1 commit into
Open
mattmuller wants to merge 1 commit into
mattmuller wants to merge 1 commit into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What kind of change does this PR introduce?
New WARN-level lint
0034_definer_function_uses_current_user.What is the current behavior?
Nothing flags
current_userused for an authorization decision inside aSECURITY DEFINERfunction. In such a functioncurrent_useris the function owner for the whole call, never the caller. A check likecurrent_user = 'admin_role'gives the same answer for every caller, so it either admits everyone or blocks everyone.session_useris not a fix either: through the Data API it is the connection role, not the end user.What is the new behavior?
The lint inspects SQL and PL/pgSQL
SECURITY DEFINERfunctions in exposed schemas (pgrst.db_schemas, defaultpublic; extension-owned functions skipped) and reports those that usecurrent_user,current_roleoruserin an authorization-like way. It readsprosrcas text, so the heuristic is intentionally narrow:'current_user',"user"and-- current_usernever match.t.user) and longer identifiers (user_id,my_current_user) never match.useris reserved in Postgres, so a bare unquoteduseris the function.=,<>,!=,in,any,like,is distinct from) and arguments topg_has_role/has_*_privilegecount. Plain reads (values (current_user)) andset col = current_userassignments, typically audit columns, are ignored.SET ROLEorSET SESSION AUTHORIZATIONare skipped.Minimal repro:
Additional context
I searched open and closed issues and PRs for
current_userandsecurity definerand found nothing proposing this. Related but different: 0028 / 0029 reportSECURITY DEFINERfunctions that are callable at all. #172 asks 0029 to skip functions with an authorization gate in the body, which is the opposite direction. #197 claims number0031, so numbers in this series may need adjusting at merge.How it was tested
test/sql/0034_definer_function_uses_current_user.sql:SECURITY INVOKERfunction; definer usingauth.uid(); identifiers inside a comment, a string literal and a declared variablecurrent_user_label, plus a parameteruser_id;insert ... values (current_user);update ... set owner_name = current_user; a function that runsset local rolefirst.current_user = 'admin_role';owner_name = current_userin a filter;pg_has_role(current_user, ...)in PL/pgSQL.auth.uid()/auth.role()returns 0 rows.Full suite passes on
supabase/postgres15.14.1.169 and 17.6.1.169, including thesplinter.sqlvalidity check.bin/check_lints.pypasses.False-positive risk. Low to moderate. Text matching cannot see dynamic SQL, so some real uses are missed. It can flag a function that deliberately checks its owner. Audit-style uses are excluded by the heuristic above.