LAFU Sales Reports

General

Anything else.

CRITICAL: is_any_staff_member() grants platform-wide admin to any org owner

Imported from GitHub issue [El-SaMa/oma#94](https://github.com/El-SaMa/oma/issues/94) by @El-SaMa. --- **Severity: Critical — active in production** \`is_any_staff_member()\` (used by ~18 RLS policies: enhance_credentials, hetzner_settings root passwords, billing_settings, support_mail_*, enhance_db_node_credentials, etc.) checks \`memberships.role IN ('owner','admin','staff')\` with **no organization filter**. Any customer who owns their own hosting org (the normal state via \`organizations.owner_user_id\`) passes this check and gets platform-wide staff access to every other customer's data. App-layer equivalent (\`resolveRoleForUser\` in \`apps/web/lib/roles.ts\`) had the identical bug. **Fix drafted, not yet deployed:** - \`packages/db/migrations/0053_fix_staff_role_scope.sql\` — redefines \`is_any_staff_member()\` to check membership in one specific staff org UUID (Lanetti, \`edb40deb-e0ac-49f6-ab39-1efee07831a7\`) - \`apps/web/lib/roles.ts\` — \`resolveRoleForUser\` now scoped to \`STAFF_ORGANIZATION_ID\` **Prerequisite:** the platform operator (\`[email protected]\`) must be added as \`owner\` of the Lanetti org first, or this fix locks out the operator's own admin access (neither \`OMA_STAFF_EMAILS\` nor \`OMA_STAFF_ORGANIZATION_ID\` is set in production, so admin access currently depends entirely on the same unscoped membership lookup). **Exposure:** currently 13 real customer accounts have unintended \`owner\`-role-driven staff access.

BugShippedGeneral·4 months ago·0

SEO audit fetches a URL before the private-address check

Imported from GitHub issue [El-SaMa/oma#159](https://github.com/El-SaMa/oma/issues/159) by @El-SaMa. --- ## What is wrong `fetchUrl` in `services/core-api/src/seo-audit.ts` requests the submitted URL, following redirects, and only then calls `resolvePublicAddresses` on the final hostname. `normalizeAuditUrl` blocks a literal private IP and `localhost`. It does not resolve the name first. `resolvePublicAddresses` asks 1.1.1.1 and 8.8.8.8, not the address the connection actually used. Any signed-in customer can submit a URL (`apps/web/app/api/ai/seo-audit/route.ts`, 12 per rate-limit window). A redirect onto a LAN address is already sent before the later check throws. When that check fails, the body is dropped and the audit says the site did not respond, so this is the portal making an internal request, not a proven database read. If the server's own DNS and 1.1.1.1 disagree, the internal response is returned in the audit. Webhooks and uptime monitors already use `assertSafePublicHttpUrl` in `services/core-api/src/platform/ssrf-url.ts`, which resolves and rejects private addresses before the request. ## Fix Resolve and reject private, link-local, and metadata addresses before connecting. Pin the connection to the checked address so a later DNS change cannot swing it. Re-check every redirect the same way. Reuse `assertSafePublicHttpUrl` rather than a second checker. ## Found Read-only review of `origin/main`, 8 Oct 2026. Not confirmed against the live server.

BugShippedGeneral·19 days ago·0
HollahoopGet yours