Skip to content
v1.10.2May 18, 2026

Massu v1.10.2

Stage C Release 2 — pre-launch audit HIGH-severity sub-stages C.3 (schema/DB, 4 items) + C.5 (security defense-in-depth, 5 of 7 items) per `docs/plans/2026-05-18-stage-c-high-batch.md` (plan token `plan-stage-c-high-batch`). 9 items shipped this release. Two C.5 items (P-H019 Ed25519 license signing + P-H022 nonce-b...

Stage C Release 2 — pre-launch audit HIGH-severity sub-stages C.3 (schema/DB, 4 items) + C.5 (security defense-in-depth, 5 of 7 items) per docs/plans/2026-05-18-stage-c-high-batch.md (plan token plan-stage-c-high-batch). 9 items shipped this release. Two C.5 items (P-H019 Ed25519 license signing + P-H022 nonce-based CSP migration) are deferred to dedicated follow-up sub-plans because each requires non-trivial server-side counterparts (P-H019: AWS Secrets Manager key + signing route; P-H022: per-page inline-script audit) that must be done with operator coordination and proper testing scope — NOT release valves per CR-46, but legitimate scope-splitting where the structural foundation needs the operator's environment access.

Added

  • website/supabase/migrations/027_drop_contact_submissions_anon_insert.sql — drops the allow_anon_insert RLS policy on contact_submissions that previously let the public anon key bypass /api/contact's rate-limit + Zod sanitization. The API route uses the service-role client (RLS-exempt), so the anon policy was unnecessary AND a security footgun. P-H021.
  • website/src/lib/ip/get-client-ip.ts — canonical client-IP extractor preferring x-real-ip (trusted on Vercel) over RIGHTMOST x-forwarded-for hop. P-H018 — replaces 19 callsites that trusted the LEFTMOST attacker-controlled XFF hop.
  • website/src/tests/get-client-ip-precedence.test.ts — 7-case drift-guard asserting precedence + AST-scan ban on any direct headers.get('x-forwarded-for') outside the helper.
  • website/src/tests/webhook-url-allowlist-completeness.test.ts — 11-case drift-guard for the new validateWebhookUrl gaps (P-H024).
  • packages/core/src/tests/memory-db-cascade-delete-session.test.ts — drift-guard for P-H011 cascade behavior (source scan + live cascade verification on a fresh DB).

Fixed

  • website/src/lib/supabase/types.ts — added trial_email_log type definition (Row/Insert/Update + Relationships) per migration 024. Removed the supabase as unknown as ... cast hack at app/api/license/activate/route.ts:421-425. Comment about "migration 023" stale-referenced removed. P-H010.
  • packages/core/src/memory-db.ts — 10 FOREIGN KEY references to sessions(session_id) now declare ON DELETE CASCADE (was: implicit RESTRICT). Closes the "DELETE FROM sessions with surviving children throws" class under PRAGMA foreign_keys = ON. Note: existing customer DBs from prior versions retain non-cascade tables (CREATE TABLE IF NOT EXISTS no-ops); fix takes effect for fresh installs from 1.10.2 onward. P-H011.
  • packages/core/src/memory-db.ts:630-657dequeuePendingSync no longer silently discards queue items at retry_count >= 10. Now emits a stderr warning with recent error messages AND inserts a cloud_sync_giveup row into analytics_events so the customer can detect silent cloud-sync failure (e.g., invalid API key for >10 cycles losing all queued observations). P-H012.
  • packages/core/src/knowledge-db.ts:107-119knowledge_schema_mismatches.source column no longer has a SQL DEFAULT that was a JS template-literal interpolation baked into the customer's SQLite at schema creation time (so later config changes were ignored). Default is now applied at INSERT time via getConfig().conventions.knowledgeSourceFiles[0] in knowledge-indexer.ts:443-447. P-H013.
  • 19 route handlers (api/settings/route.ts, api/contact/route.ts, api/evidence/route.ts, api/license/activate/route.ts, api/github-stars/route.ts, api/sso/route.ts, api/sso/callback/route.ts, api/keys/route.ts, api/keys/[id]/route.ts, api/export/route.ts, api/lemon-squeezy/webhook/route.ts, api/stripe/checkout/route.ts, api/badge/[orgSlug]/[type]/route.ts, api/invitations/accept/route.ts) — replaced request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown' with getClientIp(request). Closes the attacker-controllable IP bypass class. P-H018.
  • packages/core/src/cloud-sync.ts:98-128 — payload filter now consumes classifyVisibility() from observation-extractor.ts to drop observations whose title/detail/file_path match PRIVATE_PATTERNS (Stripe keys, env var names, file paths, Bearer tokens, etc.). Pre-fix: cloud-sync transmitted every observation to Massu's Supabase, leaking customer secrets. Now drops privately-classified observations with stderr count for transparency. P-H020.
  • website/src/app/api/license/activate/route.ts:17-39hashIp() no longer falls back to LEMON_SQUEEZY_WEBHOOK_SECRET and no longer silently uses empty pepper. IP_HASH_PEPPER is now REQUIRED; absence throws with actionable error. Closes the cross-purpose-key-reuse vulnerability where a leaked license_activation_attempts table would let attackers recover the webhook-signing secret via rainbow-table inversion. P-H023. Operator action required: set IP_HASH_PEPPER env var to a distinct random value (openssl rand -hex 32) — NOT reused from any other secret.
  • website/src/lib/validations.ts:199-260validateWebhookUrl SSRF allowlist extended: rejects 0.0.0.0/8 (was: only exact 0.0.0.0), CGNAT 100.64.0.0/10, IPv6 ULA fc00::/7, IPv6 link-local fe80::/10, IPv4-mapped IPv6 loopback ::ffff:127.x.x.x, and IPv6 ::1 (canonical form). P-H024. DNS-rebinding pin documented as follow-up (requires fetch-dispatcher rework).
  • website/src/tests/integration/license-activate.test.ts:99-110 — added vi.stubEnv('IP_HASH_PEPPER', ...) to beforeEach since P-H023 made the env var REQUIRED. Test deterministically uses a fixed pepper string.

Deferred to Follow-up Sub-Plans

  • P-H019 Ed25519 license signingplan-license-response-signing-server-side (TBD). Requires: (a) AWS Secrets Manager key creation by operator, (b) server-side signing route in website/src/app/api/license/validate/route.ts, (c) client-side verifier in packages/core/src/security/, (d) 24h grace period for existing unsigned-cache acceptance, (e) cutover smoke test against production. Current vulnerable behavior preserved until follow-up ships.
  • P-H022 nonce-based CSP migrationplan-csp-nonce-migration (TBD). Requires: (a) per-page audit of every inline <script> and <style> in website/src/app/, (b) middleware nonce generation + injection into request headers, (c) Next.js consumption pattern (read x-nonce from headers() in layout), (d) tightening CSP one-source-at-a-time with smoke testing each page, (e) drift-guard test. Current 'unsafe-inline' CSP preserved until follow-up ships.

Try this release

Install the latest version of Massu and start governing your AI development today.