Skip to content

Stop exposing ip_hash to anon and remove anon write grants - #36

Merged
drkostas merged 1 commit into
mainfrom
fix/anon-db-privileges
Oct 18, 2026
Merged

drkostas merged 1 commit into
mainfrom
fix/anon-db-privileges

Conversation

@drkostas

Copy link
Copy Markdown
Owner

Two defense-in-depth fixes on the public engagement tables (comments, reactions, the community wall, CV downloads, the moderation log), on top of the row-level security that is already there. Found by a read-only review of the site's public REST tables.

1. anon could read ip_hash

ip_hash is a salted, server-set value used only for abuse limiting and for the "delete my own comment" check, so no IP can be recovered from it, but one visitor's comments, reactions and wall notes could be linked by it. The anon role now has a column-level SELECT that omits ip_hash on the three readable tables, and no SELECT at all on the two tables that were never anon-readable.

2. anon had write grants it never used

The anon (and authenticated) role had INSERT, UPDATE and DELETE on every table and view. Row-level security refuses those writes today, but the grants should not be there. They are revoked, and default privileges no longer hand them to new tables. Every write goes through the server with the service role, which bypasses row-level security.

Code change

The two count helpers in src/lib/supabase.ts used select("*"). A column-level SELECT that omits ip_hash would deny a * read, so they now count a named column instead. The count is identical.

The grant changes are in docs/anon-privileges-hardening.sql. I dry-ran them against the live database in a rolled-back transaction and confirmed anon can read every column except ip_hash, the count helpers work, the views still read, and anon writes are denied. The grants are applied to the database once this deploys, so the live reads switch to the named-column count first.

The public engagement tables granted the anon role SELECT on ip_hash and
INSERT, UPDATE and DELETE on every table and view. ip_hash is a salted
server-set value used only for abuse limiting, so clients should never read it,
and every write already goes through the server with the service role.

The anon count helpers now count a named column instead of "*", so a
column-level SELECT that omits ip_hash does not deny them. The SQL that applies
the grant changes lives in docs/anon-privileges-hardening.sql.
@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gkos-dev Ready Ready Preview Oct 18, 2026 6:04pm UTC

@drkostas
drkostas merged commit 04e7494 into main Oct 18, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this to Todo in Pokédex Oct 26, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in Pokédex Oct 26, 2026

This branch was successfully deployed

1 active deployment
Preview — fa80c3cd Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant