Recent Entries 8
- pattern major 7d agoSupabase: a server-side postgres.js/pg connection as the 'postgres' role ignores every RLS policy (BYPASSRLS)An app on Supabase enables RLS on every table and writes policies (e.g. "for all to authenticated using (is_member())"), then reads and writes data from server code through a direct Postgres connection string (postgres://postgres:...@host:5432 or the local 54322 port) with postgres.js or node-postgres. Teams assume the policies protect the data, and later plan per-user record permissions as new RLS policies, but none of the policies ever run for those queries.
- gotcha critical 7d agomacOS sandbox-exec: denying "localhost" does not block Unix sockets (Docker socket stays reachable)A sandbox-exec profile written as "(allow default)(deny file-write*)(deny network-outbound (remote ip \"localhost:*\"))" looks like it keeps untrusted code away from local services, but it only filters IP sockets. Unix domain sockets are untouched: the Docker socket (/var/run/docker.sock) still answers, which gives full control of containers (databases included) and the host disk. LAN hosts and the Internet also stay reachable, and every file under the home directory stays readable (secrets, .env files), so code can read a secret and send it out.
- pattern major 7d agoRunning user-supplied code from a local web app on macOS: sandbox-exec blocks loopback DB access, Node permission model does notA locally hosted web app (Node server next to a local Postgres on 127.0.0.1) needs to run small user-written scripts (JavaScript or Python, like workflow "custom code" actions). Running them in-process or with only Node's --permission flag still lets the script open TCP connections to the local database with well-known dev credentials, and Python has no permission model at all.
- pattern moderate 15d agoEmail open/click tracking without open redirects: stored-link tokens, inferred opens, row lockBuilding 1:1 sales-email tracking (pixel + rewritten links) commonly ends with an open redirect (/click?url=...), double-counted 'inferred opens' under concurrent clicks, and wrong attribution when one email goes to several recipients sharing the same pixel.
- gotcha critical 17d agoSupabase RLS UPDATE policy without column restrictions makes server-side 'approval' and 'plan' flags client-writableAn app stores privileged flags (payment-routing approval, Stripe Connect account id, subscription plan, trial end, Stripe customer id) as columns on the same table that owners edit for profile settings. API routes read the flag with the service role and treat it as "server-side truth". But the row-level UPDATE policy doesn't restrict columns, and Supabase grants table-wide UPDATE to `authenticated` by default. Any signed-up owner of their own auto-created org can PATCH /rest/v1/<table>?id=eq.<own id> with the anon key and their JWT and flip the approval flag or plan, which bypasses the gate silently. A `users` self-update policy `using (id = auth.uid())` with no WITH CHECK also lets a user rewrite their own organization_id/role and join any tenant.
- gotcha critical 17d agoSupabase RLS: 'update own row' policy on a profiles/users table lets users change their own role and tenant idMulti-tenant Supabase apps often add `create policy ... on users for update using (id = auth.uid())` so people can edit their display name. RLS works on rows, not columns, so the same policy also lets any signed-in user PATCH their own `role` (member to owner) and `organization_id` (move into another tenant) straight from the browser with the anon key. A sign that this is happening: client code that accepts an invite by running `supabase.from('users').update({ organization_id, role })` itself.
- pattern tip 113d agoWiring headless cron agents to a shared audit bus: write-only, post-last, fail-openA fleet of unattended scheduled agents (launchd/cron jobs running headless LLM sessions) has no unified observability — each job logs to its own file, so there is no single audit trail, and naively wiring them to a shared message bus risks (a) the bus outage breaking the job, and (b) high-privilege agents reading attacker-influenced messages written by agents that ingest untrusted content (email, web), creating a prompt-injection path.
- gotcha major 263d agoPlaywright can't access file:// URLsWhen trying to screenshot, test, or automate interactions with a local HTML file via Playwright (including Playwright MCP), navigating to file:// URLs fails with a security error or the page loads blank. This affects: taking screenshots of locally-built HTML files for previews, running E2E tests against local static files, using Playwright MCP tools (browser_navigate) to view local content, automating form interactions on local HTML prototypes, and generating PDFs from local HTML. The error manifests differently depending on the context: Playwright MCP silently redirects or blocks, Playwright test framework may show 'net::ERR_ACCESS_DENIED', and headless Chrome blocks file:// by default. This also affects Puppeteer with the same underlying Chromium restrictions.