Repository navigation
Lock down SECURITY DEFINER functions and privileged columns - #653
Merged
Merged
Conversation
- Revoke internal SECURITY DEFINER functions from anon/authenticated:
withdraw_balance (any user, any amount; a negative amount minted
balance), create_notification (any user), the gig-usage counters,
get_api_key_user, update_api_key_last_used, the affiliate offer
counter, moderate_affiliate_application (caller-supplied seller id),
bump_autoblog_integration, and every trigger function.
- blocked_user_ids / users_are_blocked answer only for the caller.
- New functions are no longer executable by PUBLIC/anon/authenticated by
default; browser RPCs need an explicit GRANT.
- funding_payments: UPDATE and INSERT were open to anyone and SELECT
exposed contributor emails; now own rows + service role.
skill_security_scans: the 'service role' policy had no role, so anyone
could write scan results.
- Pin privileged columns behind update-own policies: profiles.is_admin,
credits, rating/follow counters, referral code; subscriptions (users
may only toggle cancel_at_period_end); invoice and escrow money fields
and paid/funded status; bounty payout status; application status
(applicant may only withdraw or re-open); testimonial text and rating;
other people's messages; listing counters and scan status; gig views
and future-dated boosts.
- Login redirect also rejects tabs/newlines ('/\t/host' parses to
'//host').
Migration applied by hand on dev2 (backup taken first).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ThreatCrush Security Scan60 finding(s) HIGH/CRITICAL: 1 | MEDIUM: 12 | LOW: 47
…and 10 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
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.
Security audit 2026-10-26. 56 SECURITY DEFINER functions in
publicwere executable by anon/authenticated; 9 remain, all public read-only or scoped to the caller.Dangerous functions (now service-role only)
withdraw_balance(p_user_id, p_amount): anyone could zero any user's cached balance, or pass a negative amount to mint one. (Withdrawals check the real LNbits balance, so no sats left, butwallets.balance_satsis read by affiliate commission accounting.)create_notification(any user): anon could send notifications to anyone.increment_gig_usage/increment_gig_usage_for_active/decrement_gig_usage: reset or inflate any user's monthly free-tier counter.get_api_key_user,update_api_key_last_used,moderate_affiliate_application(caller-chosen seller id),increment_affiliate_offer_total_affiliates,bump_autoblog_integration, and all 36 trigger functions.blocked_user_ids/users_are_blockednow answer only about the caller (server keeps full access).grant execute ... to anon, authenticated.Policies / privileged columns
profiles.is_adminwas writable by the user (the /admin, payouts and email broadcast gate); alsocredits, rating/follow counters,referral_code. Pinned.subscriptions: users could PATCHplan/status/current_period_end. Now onlycancel_at_period_end.funding_payments: UPDATEUSING (true)and INSERTtruefor everyone, SELECT exposedcontributor_email. Now own rows + service role.skill_security_scans: "Service role manages scans" had no role, so anyone could write scan results.payout_status'paid' likewise. Applicants may only withdraw/re-open. Testimonial text/rating, other people's messages, listing counters + scan status, gig views pinned.redirectalso rejects tabs/newlines.Applied by hand on dev2 (schema backup first). Live check (anon key + throwaway users, cleaned up): internal RPCs 42501; is_admin/credits/plan/invoice paid/amount/self-accept all unchanged after PATCH; withdraw, reject, cancel, feed, subscriptions and profile APIs still work. Abuse check: one admin (Anthony), 0 credits, 0 non-free subscriptions, all 267 paid invoices carry a CoinPay id, no unreferenced paid funding rows.
🤖 Generated with Claude Code