Conversation
Adds three migrations for server-side signer security: - 1_rls_and_policies: search_path hardening, WITH CHECK tightening on accounts/accounts_to_channel/customers/profile, draft.created_by_user_id column + policy, auto-interaction ownership trigger, drop user INSERT on signing_audit_log, FORCE RLS on sensitive tables. - 2_rpcs: authorize_draft_publish / authorize_auto_interaction SECURITY DEFINER RPCs that enforce ownership invariants for cron paths. - 3_grants_and_audit: revoke decrypted view grants from anon/authenticated, add actor_user_id + source columns to signing_audit_log, revoke vault USAGE from authenticated, narrow pgsodium_keyiduser to service_role. Per-action JWT minting replaces cron service-role bypass (see signer commit). decrypted_account(uuid) EXECUTE deliberately retained for authenticated (RPC self-filters on auth.uid(); revoking would break the signer path). Phase 6 operator actions (KEK wrapping, service-role rotation, cron secret vault migration) are documented in .context/phase-6-operator-actions.md and left as inline comments at the bottom of migration 3.
Replaces the signer service-role bypass (any holder of service_role could sign as any account) with a per-action JWT flow: - farcaster-signer/lib/auth.ts: delete the service_role branch. Signer now always validates via supabase.auth.getUser(). Extracts a validated `source` claim from the JWT for audit attribution. - farcaster-signer/lib/accounts.ts: userId is required; reads via decrypted_account(uuid) RPC; defense-in-depth check that account.user_id matches the JWT sub. - farcaster-signer/lib/audit.ts: constructs a service-role client internally for signing_audit_log INSERTs (the user-INSERT policy was dropped for log integrity). Writes actor_user_id + source. - publish-cast-from-db / process-auto-interactions: call the new authorize_draft_publish / authorize_auto_interaction RPCs before signing; mint a 60s-TTL HS256 JWT locally using SUPABASE_JWT_SECRET (sub = validated owner_user_id); pass it to the signer instead of the service_role key. - _shared/redact.ts: redactHeaders / redactSecrets helpers applied to error-log dumps so axios errors no longer leak Authorization / Neynar api_key headers into Sentry. Requires the three db: migrations to have applied first so the authorize_* RPCs exist and the signing_audit_log schema includes actor_user_id / source. Deploy atomically with migrations.
- mcp-server: per-tool assertScope gating for every MCP tool. Tokens without explicit scope claims fall back to read-only DEFAULT_SCOPES (['read:accounts','read:casts']) so approving an MCP client no longer equals full session power. 401 response no longer echoes the bearer prefix. - oauth/decision: validates that requested scopes are a subset of what was shown on the consent page; defensively passes scopes through to approveAuthorization. - api/auth/siwe: stop logging full request.headers (session cookie leak). - sentry.server.config + sentry.edge.config: beforeSend scrubber that redacts Authorization/apikey/cookie headers, JWT-shaped (eyJ...) and sb_... tokens across event.extra, event.breadcrumbs, event.exception.values[*].stacktrace.frames[*].vars, and event.contexts. Wrapped in try/catch so a scrub failure never blocks Sentry. instrumentation-client.ts is deliberately untouched per scope (no client-side changes in this hardening pass).
Adds a Node-only migration linter that enforces: - security_invoker=true on new public views (grandfathered for existing views where the flag is set in a later migration) - SET search_path on every new CREATE FUNCTION - no WITH CHECK (true) on new policies (tables can opt in with an inline 'lint-allow-with-check-true' comment, e.g. channel) - no bare JWT-shaped literals in migration SQL Runs on push + PR for paths that touch supabase/migrations or the script itself. Uses --ignore-before=20260423 so pre-existing legacy violations are visible but not blocking; regressions in new migrations fail the build. Pre-existing flagged issues (not fixed here, intentionally): - 17 legacy items in pre-2026 migrations (reported only) - public.channel retains WITH CHECK (true) with an allow-comment (channel is a shared protocol namespace; no user secret material)
Bug caught by local verification: the project's ALTER DEFAULT PRIVILEGES (see 20231201175719_schema_test.sql:202) grants ALL on newly-created functions to anon and authenticated. The previous REVOKE ALL ... FROM PUBLIC did NOT remove those role-specific grants — so authorize_draft_publish and authorize_auto_interaction were effectively callable by any authenticated user. An attacker could have called the RPCs directly, reading owner_user_id and bypassing the cron-only trust boundary. Explicitly revoking from anon and authenticated enforces the intended "service_role-only" posture. Verified via scripts/verify-signer-hardening.sh.
Adds scripts/verify-signer-hardening.sh — a bash script that seeds two test users (attacker + victim) against a local supabase stack and exercises every hijack vector the hardening claims to close: - V3 (draft row-planting): RLS WITH CHECK and authorize_draft_publish RPC both reject cross-user INSERTs independently. - V4 (auto-interaction hijack): trigger rejects mismatched contents.sourceAccountId and null; RPC rejects even when the trigger is bypassed via session_replication_role=replica. - V11 (audit tamper): authenticated role cannot INSERT into signing_audit_log; service_role can (used by signer after Bug 2 fix). - V16 (FORCE RLS): verifies all 5 sensitive tables. - Grant posture: decrypted_accounts view + authorize_* RPCs locked down to the right roles; vault USAGE revoked; decrypted_account RPC retained for authenticated. Usage: supabase start && supabase db reset && bash scripts/verify-signer-hardening.sh All 17 assertions currently pass against the migrations in this branch.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
Reflects the post-migration schema: - draft.created_by_user_id (NOT NULL, default auth.uid()) - signing_audit_log.actor_user_id and source columns - authorize_draft_publish(p_draft_id) and authorize_auto_interaction(p_list_id) RPCs Generated via `supabase gen types typescript --project-id <ref> --schema public`.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
Supabase reserves the SUPABASE_* env-var prefix for auto-injected vars and the CLI rejects `supabase secrets set SUPABASE_JWT_SECRET=...` with "Env name cannot start with SUPABASE_, skipping". Earlier checklist text (now corrected) assumed SUPABASE_JWT_SECRET would be auto-provided — that is not the case for projects migrated to JWT signing keys, where SUPABASE_SECRET_KEYS is auto-provided in JWKS form instead. Both cron functions (publish-cast-from-db, process-auto-interactions) now read LEGACY_JWT_SECRET. Operator must set it once via: supabase secrets set LEGACY_JWT_SECRET=<legacy-jwt-secret-from-dashboard> The value is the project's "Legacy JWT secret" from Dashboard -> Project Settings -> JWT Keys (the same secret that signs the legacy service_role/anon JWTs). Caught while smoke-testing the deployed cron flow: a freshly scheduled draft was being marked 'failed' because mintUserJwt threw on the missing env var, and publishDraft's catch block flipped status -> failed.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
gotrue's AccessTokenClaims Go struct expects 'scope' to be a
space-delimited string per OAuth 2.0 (RFC 6749 §3.3). We were
passing an object ({ account_id, draft_id }), causing the signer's
supabase.auth.getUser() to reject every cron-minted token with:
invalid JWT: unable to parse or verify signature, token is malformed:
could not JSON decode claim: json: cannot unmarshal object into Go
struct field AccessTokenClaims.scope of type string
Renaming our custom claim to 'cron_meta' avoids the reserved name and
keeps the bookkeeping object intact for audit/debugging purposes.
Caught while smoke-testing the deployed cron flow against prod after
LEGACY_JWT_SECRET was correctly set. Diagnostic console.log was added
during debugging; removed in this same commit since the actual error
turned out to be claim shape, not secret value.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
After exhausting debug cycles on the legacy HS256 secret value mismatch, pivoted to ES256 per the project's already-active JWT signing keys infrastructure. ES256 is the documented future-proof path post-migration: https://supabase.com/docs/guides/auth/signing-keys Setup performed via Supabase Management API: 1. Generated a dedicated ES256 (P-256) keypair locally (Node crypto). 2. Imported the private JWK as a standby signing key on the project, getting kid `5789fc0d-8d87-467f-bc37-97d8fdb20df6`. 3. Verified the public side appears in https://<ref>.supabase.co/auth/v1/.well-known/jwks.json 4. Stored the private JWK as the function secret `CRON_SIGNING_PRIVATE_JWK`. mintUserJwt now: - Reads `CRON_SIGNING_PRIVATE_JWK`, parses to JWK, imports for ECDSA P-256. - Signs JWT with `alg: ES256` and the JWK's `kid` in the header. - Drops the LEGACY_JWT_SECRET dependency; that secret can be removed from the project's edge-function env (operator action). Signer's `supabase.auth.getUser()` validates automatically via JWKs lookup by kid — no signer-code change needed. The new key is `standby` so it verifies but does not displace the project's current ES256 Auth signing key (kid `b6908320-...`). Verified end-to-end: scheduled draft 18a46cef-... published successfully at 2026-05-03 19:30 UTC, audit log shows source='cron:publish' with success=true and actor_user_id populated. Followups (separate change): - Once stable for ~1 week, remove LEGACY_JWT_SECRET function secret. - Operator can then safely revoke the legacy HS256 signing key (`140a997e-...`) after migrating service_role/anon to sb_secret_*/sb_publishable_*.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
Three small fixes after codex flagged stale comments + a small info leak:
- farcaster-signer/lib/auth.ts: doc-string said cron mints HS256, but it
now mints ES256. Updated to reflect the post-debug state.
- mcp-server/lib/auth.ts: removed `console.log('[auth] Received auth
header:', authHeader.slice(0, 20) + '...')`. The 20-char slice exposed
the JWT header + first ~14 bytes of payload, contradicting our
scope-cleanup goal (mcp-server/index.ts:124-134 already strips this
from the response body). Also dropped a few adjacent debug console.log
lines that leaked token length / user-id / scopes.
- publish-cast-from-db: replaced the trailing demo curl comment that
included a hardcoded `eyJ...` JWT (a public Supabase demo token, but
a future log dump could match the JWT-shape regex). Updated to use
`$SUPABASE_ANON_KEY` placeholder.
- Renamed `mintUserJwt`'s param `scope` → `cronMeta` in both cron files
to match the JWT claim name (which we changed in commit efe283a to
avoid OAuth's reserved `scope` claim).
No functional change; functions redeployed for cosmetic + log-leak fix.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. [claude at 2026-05-03T19:50:09Z]: I'll analyze this and get back to you. |
`.claude/` contains per-machine settings (MCP permission allowlist, runtime PID lock files) that should never enter the repo. Adding it to .gitignore so accidentally-untracked files there won't show up in `git status` for any contributor running Claude Code.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
The latest Supabase CLI (v2.90+) dropped the legacy `--force` flag. Job 74138951854 failed with `unknown flag: --force` because the runner pulls `supabase/setup-cli@v1` with `version: latest`. The equivalent non-interactive flag is `--yes`, which answers Y to all prompts. Reference (CI failure log): Run supabase db reset --force unknown flag: --force ##[error]Process completed with exit code 1.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
After fixing the --force flag, the next CI run failed in `supabase start` with: failed to start docker container "supabase_inbucket_herocast": failed to bind host port for 0.0.0.0:54324:172.18.0.5:8025/tcp: address already in use `supabase start` retried after an initial container hiccup and the inbucket port was still bound from the previous attempt, killing the whole stack startup. Signer tests only exercise db + auth + edge-runtime. Excluding the unused services (inbucket/studio/storage-api/realtime/imgproxy/etc) removes the failure surface and trims runner startup time.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
The signing-service-tests workflow had never passed (every run since
the workflow was added has failed). Root cause for the latest seed.ts
failure:
Failed to create account ...: {"code":"P0002","message":"query returned no rows"}
The bare `INSERT INTO pgsodium.key (id, key_type, key_id, key_context)`
in `pgsodium_seed_key.sql` populated the row but pgsodium's
crypto_aead_det_encrypt could not derive `raw_key` from the bare
metadata, so the account-encrypt trigger raised P0002 on every INSERT.
Switching to `pgsodium.create_key('aead-det', 'herocast_encryption_key')`
generates a properly initialized key (raw_key + nonce + sequence). We
then UPDATE the auto-generated id to the deterministic UUID referenced
by the trigger functions (dcd0dca7-...), preserving the existing
trigger contracts.
Idempotent: returns early if the deterministic UUID already exists;
otherwise cleans up any prior partial seed, creates the key, reassigns.
|
Claude finished @hellno's task —— View job Security Hardening PR Review
|
Root cause of CI failure: in the Supabase CLI image, the `postgres` role
is not a true superuser and does not own pgsodium internals. After
`supabase db reset` re-locks pgsodium, the post-reset psql step fails
with "permission denied for table key" when trying to seed the
encryption key via DELETE/UPDATE on pgsodium.key — and the seed.ts step
then fails with P0002 ("query returned no rows") at encrypt time.
Move the key seed into `supabase/seed.sql` (auto-applied by `db reset`
with the migration-runner role, which DOES have pgsodium write access).
Verified locally:
- encrypt_test returns valid ciphertext after `supabase db reset`
- seed.ts creates both test accounts
- full deno test suite: 35 passed, 0 failed, 9 e2e-ignored
Also re-grant `pgsodium_keyiduser` to `authenticated` in seed.sql since
migration 20260423000003 revokes it for production hardening (tests
need it back for the decrypt path).
Drop the redundant `psql ... pgsodium_seed_key.sql` line from CI; the
grants psql call is kept (it succeeds for the GRANT ROLE membership
and silently no-ops on the function-EXECUTE grants the postgres role
lacks ownership for, which are not on the tested code path anyway).
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
Earlier attempt put the key seed in supabase/seed.sql, but in the
Supabase CLI image used by CI the post-migration `postgres` role lacks
pgsodium_keymaker membership — INSERT/UPDATE on pgsodium.key fails with
SQLSTATE 42501 "permission denied for table key", which surfaces in
seed.ts as P0002 "query returned no rows" from the encrypt trigger.
Move the seed into a migration. Migrations apply with the migration-
runner role's elevated privileges, where pgsodium.create_key() (a
SECURITY DEFINER pgsodium-owned function) and the subsequent UPDATE on
pgsodium.key both succeed. Idempotent guard means it's a no-op against
the prod database that already has the key.
Verified locally:
- `supabase db reset` applies the new migration cleanly
- encrypt path round-trips: crypto_aead_det_encrypt('test', ...) returns
valid ciphertext via the literal UUID dcd0dca7-...
Empty out supabase/seed.sql since the key seed no longer lives there.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |
Migration approach (commit 039a5ba) hit the same SQLSTATE 42501 wall: the migration runner role in CI's Supabase image also lacks pgsodium write access — `permission denied for table key` even when the seed runs as part of an applied migration. (Locally `postgres` happens to be a member of pgsodium_keymaker so the same migration succeeds, but that membership is absent in the CI image.) The supabase_admin role IS the local-dev superuser and has full pgsodium privileges. Its password matches the project-wide PGPASSWORD default in the supabase CLI image, so we can connect via -U supabase_admin without extra setup. Use that connection for the grants + seed step. Drop the migration that tried to do the seed under the migration-runner role. Verified locally: `psql -U supabase_admin` applies pgsodium_seed_key.sql cleanly and the resulting key is queryable as the postgres role afterwards.
|
Claude finished @hellno's task —— View job Security Hardening PR ReviewI'll review this comprehensive security hardening PR that addresses multiple vulnerability vectors. Here's my analysis plan: Review Checklist
✅ Comprehensive Security AnalysisThis PR demonstrates exceptional security engineering with comprehensive defense-in-depth across multiple layers. Here's my detailed assessment: Database Migrations - Outstanding ⭐⭐⭐⭐⭐Migration 1 (RLS & Policies):
Migration 2 (Authorization RPCs):
Migration 3 (Grants & Audit):
Edge Function Security - Exceptional ⭐⭐⭐⭐⭐Authentication & Authorization (supabase/functions/farcaster-signer/lib/auth.ts:39-95):
Account Access (supabase/functions/farcaster-signer/lib/accounts.ts:23-83):
Audit Logging (supabase/functions/farcaster-signer/lib/audit.ts:72-111):
Cron Functions - Secure Implementation ⭐⭐⭐⭐publish-cast-from-db (lines 148-177, 310-327):
process-auto-interactions (lines 191-215):
MCP Server - Proper Scope Enforcement ⭐⭐⭐⭐Scope Management (supabase/functions/mcp-server/lib/scopes.ts:5-39):
Request Handling (supabase/functions/mcp-server/index.ts:188-202):
Infrastructure & DevOps - Production Ready ⭐⭐⭐⭐⭐Verification Script (scripts/verify-signer-hardening.sh):
Migration Linter (scripts/lint-supabase-migrations.mjs):
Logging Security (supabase/functions/_shared/redact.ts):
🔍 Code Quality AssessmentStrengths
Minor Observations
Test Coverage - Comprehensive ⭐⭐⭐⭐⭐The verification script provides exceptional test coverage:
🚀 Final AssessmentThis PR represents world-class security engineering with:
Recommendation: APPROVE - This PR significantly strengthens the application's security posture while maintaining operational excellence. The atomic deployment requirement is well-documented and the comprehensive verification script provides confidence in the implementation. |

Summary
Closes the signer-key hijack and bypass vectors identified in the audit. Server-side / DB / infra only — zero client-side changes.
Vectors closed: V2 (signer service-role bypass), V3 (cast-hijack via draft row-planting), V4 (auto-interaction hijack via unchecked
contents.sourceAccountId), V8 (SIWE header log), V9 (decrypted view grants), V10 (decrypted_account RPC EXECUTE), V11 (audit-log tamper), V12 (audit attribution desync), V13 (MCP per-tool scope enforcement), V14 (vault USAGE), V15 (MCP bearer echo), V16 (FORCE RLS), V18 (search_path).Phase 6 (KEK wrapping, full external KMS) intentionally out of scope —
.context/post-merge-checklist.mddocuments the residual gap and operator-only follow-ups.Do not merge until atomic deploy executed
This PR is non-atomic across migrations + edge-function deploy. A gap in either direction breaks signing in prod:
decrypted_accountsview REVOKEd fromauthenticated).authorize_*RPCs don't exist).Pre-merge state (already done)
service_role)cron.jobIDs 3 and 11 disabled in prod — V3 and V4 are unreachable right nowbash scripts/verify-signer-hardening.sh)user_idrows on tightened tables, 0 mismatched auto-interaction listsINSERT/UPDATEon tightened tables already setsuser_id = auth.uid()or relies on the column DEFAULT — no breakage expectedDeploy plan
See
.context/post-merge-checklist.md(workspace-local). Short version:supabase db push --linked.farcaster-signer,publish-cast-from-db,process-auto-interactions,mcp-server.cron.jobIDs 3 and 11.src/common/types/database.types.tsand commit as a follow-up.Operator guardrails (do NOT do these post-merge)
140a997e-…) — breaks cron-minted JWTs, the JWT-shapedservice_roleAPI key, and the JWT-shapedanonAPI key simultaneously.service_role/anontosb_secret_…/sb_publishable_…until the cron flow is migrated to ES256 (follow-up PR; full plan in checklist § 6.1).Follow-up PR (week 2-3)
auth.getUser()→auth.getClaims()for local JWKS verification.Test plan
bash scripts/verify-signer-hardening.sh— 17/17 passfarcaster-signerfarcaster-signer401 rate as canary for future legacy-key revocation