Revoke default PUBLIC EXECUTE on SECURITY DEFINER functions#362
Merged
Revoke default PUBLIC EXECUTE on SECURITY DEFINER functions#362
Conversation
PostgreSQL grants EXECUTE to PUBLIC by default on new functions, which meant any role on the cluster could invoke a CustomRole SECURITY DEFINER function. Emit REVOKE ALL FROM PUBLIC before the GRANT so only the owning CustomRole can execute it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mahlunar
approved these changes
Apr 22, 2026
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.
Summary
EXECUTEtoPUBLICby default on every new function. For CustomRole-managed SECURITY DEFINER functions (which typically run as an elevated owner likerds_superuserorrds_pgaudit), this meant any role on the cluster could invoke them — only the internal predicate checks (if any) stood between an arbitrary caller and the elevated action.REVOKE ALL ON FUNCTION ... FROM PUBLICas the function owner before the existingGRANT EXECUTE TO <roleName>so only the owning CustomRole (and roles granted membership in it) can call the function.execWithRolelike the surrounding DDL and is idempotent, so re-syncs stay consistent.Test plan
go build ./...andgo vet ./pkg/postgres/...POSTGRESQL_CONTROLLER_INTEGRATION_HOST=localhost:5432 go test ./pkg/postgres/(full package, all pass)TestSyncDatabaseFunctions_revokesPublicExecuteasserts PUBLIC has no EXECUTE after sync while the target role still does🤖 Generated with Claude Code
Note
Medium Risk
Touches database privilege/ACL logic for SECURITY DEFINER functions; a mistake could break callers or unintentionally change access, though the change is narrowly scoped and covered by a new integration test.
Overview
SyncDatabaseFunctionsnow runsREVOKE ALL ON FUNCTION ... FROM PUBLIC(as the function owner) after ensuring ownership, removing PostgreSQL’s defaultPUBLICEXECUTE grant on newly created SECURITY DEFINER functions before re-grantingEXECUTEto the managed custom role.Adds an integration test asserting the target role retains
EXECUTEwhilePUBLICdoes not, including a helper that correctly detects implicit default ACLs whenproaclisNULL.Reviewed by Cursor Bugbot for commit aeb9125. Configure here.