0028/0029 silently report zero findings for projects using a custom PostgREST request role
Maintainer thường phản hồi trong vòng 1 ngày
@sidgaikwad đang làm issue này rồi.
Từ ngày 15/9/2026.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 68/100
Hướng nghiên cứu
Bắt đầu với các function lint 0028 và 0029, đồng thời kiểm tra các vị từ đặc quyền role được hardcode của chúng. So sánh truy vấn request-role được đề xuất với hành vi hiện tại, sau đó xác minh rằng các role PostgREST tùy chỉnh tạo ra findings mà không có các function trùng lặp và rằng các findings hiện có của authenticated role vẫn được bao phủ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
0029_authenticated_security_definer_function_executable (and 0028 for anon) decide exposure with a hardcoded role literal:
pg_catalog.has_function_privilege('authenticated', p.oid, 'EXECUTE')
For a project that runs signed-in requests as a custom PostgREST role — a supported pattern, via the custom_access_token auth hook rewriting the role claim — this predicate is false for anything granted only to that custom role. The lint then reports zero findings, which is indistinguishable from "correctly remediated".
Why this is worse than an ordinary false negative
The failure mode is silent and it looks like success. A project that adopts a custom request role will typically:
- create the role and make it a member of
authenticated(so it inherits existing table/RLS grants), - move
EXECUTEgrants fromauthenticatedonto it.
Step 2 is exactly what drops these lints to 0. Role membership doesn't rescue the check, because it only runs one way: the custom role inherits from authenticated, so has_function_privilege('authenticated', …) stays false for a grant held solely by the custom role.
The result is a security category that reads 0 because the project changed how it authenticates, at the moment its exposure surface stopped being visible. In a project I work on, this category reported 0 while several hundred SECURITY DEFINER functions were executable by the actual request role — including internal helpers that were explicitly revoked from PUBLIC, anon, authenticated and were believed closed.
Suggested fix
Enumerate the roles the API can actually assume rather than naming one. authenticator is the login role PostgREST connects as, and it can only SET ROLE into roles it is a member of, so that set is discoverable:
-- roles the API can switch into, instead of the literal 'authenticated'
WITH request_roles AS (
SELECT r.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles r ON r.oid = m.roleid
JOIN pg_catalog.pg_roles grantee ON grantee.oid = m.member
WHERE grantee.rolname = 'authenticator'
AND r.rolname <> 'anon' -- 0028 covers the anonymous side
)
SELECT ...
FROM pg_catalog.pg_proc p
CROSS JOIN request_roles rr
WHERE p.prosecdef
AND pg_catalog.has_function_privilege(rr.rolname, p.oid, 'EXECUTE')
...
That is a superset of today's behaviour: authenticated is itself a member of authenticator, so every finding the lint reports now is still reported. It only adds the custom roles that are currently invisible.
Two details worth deciding on:
- Deduplication — a function granted to two request roles should surface once.
EXISTS (SELECT 1 FROM request_roles …)avoids the cross-join fan-out if the detail isn't wanted. - Naming the role in the message — the remediation text currently says "the
authenticatedrole". Reporting which role actually holds the grant would make the finding actionable for these projects.
Scope
Both function lints are affected symmetrically. The other lints that name a role literal (has_table_privilege/has_column_privilege/policy roles) are not affected in the same way provided the project leaves table and column grants on authenticated and lets the custom role inherit them — which is the natural setup. Worth confirming, but the function lints look like the load-bearing case.
Happy to open a PR if the approach seems right.
- Ngôn ngữ chính
- PLpgSQL
- Star
- 284
- Fork
- 110
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của supabase/splinter
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 69/100
supabase/splinter#206 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
0002_auth_users_exposed false positive: pg_depend join lacks a refclassid filter (cross-catalog OID collision)Có thể đã có người làm @tushardev-365 đã nhận 96 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 40/100
supabase/splinter#210 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
0030_autovacuum_disabled misses tables where autovacuum_enabled is set to off, 0 or noCó thể đã có người làm @RaphaelFakhri đã nhận 9 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 35/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Proposal: lint for RLS policies whose role lacks the table privilege (policy_without_privilege)Có thể đã có người làm @larik15 đã nhận 29 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 1/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của supabase/splinter
Issue tương tự
-
`HandleEmptyInListsPlugin` / `SafeNullComparisonPlugin` skip expressions nested in `eb.selectFrom(...)` subqueriesCó thể đã có người làm @superbot-helper đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
kysely-org/kysely#2216 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
scylladb/kafka-connect-scylladb#297 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
--dry-run runs the real operation in ruvector migrate, ruvector backup restore and deployment deployCó thể đã có người làm @tanishqbaweja đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
GoogleCloudPlatform/spanner-migration-tool#1479 ·
Maintainer thường phản hồi trong vòng 8 ngày