Session expiry deletes all resource sessions & HTTP cookie domain broken for non-SSL resources #204

Closed
opened 2026-04-05 17:02:28 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @Abhinav-kodes on 2/25/2026

Describe the Bug

While investigating the session logic (which likely contributes to issues like #2488), I found two critical bugs in server/auth/sessions/resource.ts that break session persistence:

Bug 1 — Session DELETE wipes entire resourceSessions table

File: server/auth/sessions/resource.ts
Function: validateResourceSessionToken

When a resource session is expired, the DELETE query uses a tautological WHERE clause: (Line - 90)

.where(eq(resourceSessions.sessionId, resourceSessions.sessionId))

This compares the column to itself, generating WHERE session_id = session_id (always true), which deletes ALL rows in the resourceSessions table, not just the expired one.
Every active session for every user on every resource is wiped whenever any single session expires.

File: server/auth/sessions/resource.ts
Function: serializeResourceSessionCookie

In the HTTP (non-SSL) path, the cookie string has a broken template literal: (Line - 184)

`... Path=/; Domain=$domain}`                           
//                   ^ missing opening brace — interpolation never happens

The browser receives Domain=$domain} as a literal string, rejects it, and never sends the cookie back — leaving HTTP resources perpetually unauthenticated.

Environment

  • OS Type & Version: Pop!_OS 22.04 LTS (Local Development Environment)
  • Pangolin Version: 1.15.4 (via dev branch Docker build)
  • Gerbil Version: 1.3.0
  • Traefik Version: 3.6.8
  • Newt Version: 1.9.0
  • Olm Version: N/A

To Reproduce

Bug 1: The Tautological Session Delete

  1. Authenticate and create at least two valid resource sessions in the database (e.g., log in as two different users, or access two different protected resources).
  2. Wait for one session to expire, then have that user make a request to the protected resource (triggering validateResourceSessionToken with the stale token).
  3. Query the resource_sessions database table.
  4. Observation: Notice that all sessions have been wiped from the table, logging everyone out, rather than just the single expired session.

Bug 2: The HTTP Cookie Domain Typo

  1. Configure a dummy resource to be served over standard HTTP (disable SSL).
  2. Attempt to authenticate to the resource via the web browser.
  3. Open the browser's Developer Tools -> Network tab and inspect the Set-Cookie response header.
  4. Observation: The domain attribute is literally set to Domain=$domain} instead of the parsed hostname (e.g., Domain=localhost). The browser subsequently rejects the cookie.

Expected Behavior

1. Session Deletion: When a single resource session reaches its expiration time, only that specific session's row should be deleted from the resourceSessions database table. All other valid user sessions across the platform should remain completely untouched and active.

2. HTTP Cookie Domain: When a user authenticates to a resource over standard HTTP, the Set-Cookie header should correctly interpolate the domain string (e.g., Domain=example.com or Domain=localhost). This ensures the browser properly accepts the cookie and maintains the user's authentication state for subsequent requests.

*Originally created by @Abhinav-kodes on 2/25/2026* ### Describe the Bug While investigating the session logic (which likely contributes to issues like #2488), I found two critical bugs in `server/auth/sessions/resource.ts` that break session persistence: ## Bug 1 — Session DELETE wipes entire resourceSessions table **File:** `server/auth/sessions/resource.ts` **Function:** `validateResourceSessionToken` When a resource session is expired, the DELETE query uses a tautological WHERE clause: (Line - 90) ```ts .where(eq(resourceSessions.sessionId, resourceSessions.sessionId)) ``` This compares the column to itself, generating WHERE session_id = session_id (always true), which deletes ALL rows in the resourceSessions table, not just the expired one. Every active session for every user on every resource is wiped whenever any single session expires. ## Bug 2 — HTTP resource cookie set with broken Domain **File:** ` server/auth/sessions/resource.ts` **Function:** `serializeResourceSessionCookie` In the HTTP (non-SSL) path, the cookie string has a broken template literal: (Line - 184) ```ts `... Path=/; Domain=$domain}` // ^ missing opening brace — interpolation never happens ``` The browser receives Domain=$domain} as a literal string, rejects it, and never sends the cookie back — leaving HTTP resources perpetually unauthenticated. ### Environment - **OS Type & Version:** Pop!_OS 22.04 LTS (Local Development Environment) - **Pangolin Version:** 1.15.4 (via `dev` branch Docker build) - **Gerbil Version:** 1.3.0 - **Traefik Version:** 3.6.8 - **Newt Version:** 1.9.0 - **Olm Version:** N/A ### To Reproduce **Bug 1: The Tautological Session Delete** 1. Authenticate and create at least two valid resource sessions in the database (e.g., log in as two different users, or access two different protected resources). 2. Wait for one session to expire, then have that user make a request to the protected resource (triggering `validateResourceSessionToken` with the stale token). 3. Query the `resource_sessions` database table. 4. **Observation:** Notice that *all* sessions have been wiped from the table, logging everyone out, rather than just the single expired session. **Bug 2: The HTTP Cookie Domain Typo** 1. Configure a dummy resource to be served over standard HTTP (disable SSL). 2. Attempt to authenticate to the resource via the web browser. 3. Open the browser's Developer Tools -> Network tab and inspect the `Set-Cookie` response header. 4. **Observation:** The domain attribute is literally set to `Domain=$domain}` instead of the parsed hostname (e.g., `Domain=localhost`). The browser subsequently rejects the cookie. ### Expected Behavior **1. Session Deletion:** When a single resource session reaches its expiration time, only that specific session's row should be deleted from the `resourceSessions` database table. All other valid user sessions across the platform should remain completely untouched and active. **2. HTTP Cookie Domain:** When a user authenticates to a resource over standard HTTP, the `Set-Cookie` header should correctly interpolate the domain string (e.g., `Domain=example.com` or `Domain=localhost`). This ensures the browser properly accepts the cookie and maintains the user's authentication state for subsequent requests.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/pangolin#204