Skip to content

Security Review

Marty McEnroe edited this page Aug 6, 2026 · 4 revisions

Security Review

Facts for a security reviewer assessing palaestra.thrivetech.ai. Every item below is verifiable against published source, linked at the bottom.

Service

Type Browser-based simulation. Single-page application plus JSON API.
Hosting Cloudflare Workers. Static assets and API served from one Worker.
Domain palaestra.thrivetech.ai
Data stores Cloudflare D1 (SQLite), Cloudflare R2 (scenario files)
Commercial model None. Nothing is sold. No payment processing exists.

Outbound network

Destination When Purpose
www.linkedin.com Sign-in only OAuth consent, as a top-level browser navigation
api.linkedin.com Sign-in only Server-to-server exchange of authorization code for name and email

The server contacts no other host. The browser contacts no host other than palaestra.thrivetech.ai.

There is no CDN, analytics, web font, advertising network, tracking pixel, or error-reporting service. The only external strings in the built JavaScript are the SVG XML namespace (www.w3.org) and two documentation URLs inside a markdown library's error messages. None is fetched at runtime.

Sign-in flow

Four hops. Each line is the host contacted and by whom.

# Who Host contacted Request
1 Browser palaestra.thrivetech.ai GET https://palaestra.thrivetech.ai/api/auth/login
2 Browser www.linkedin.com Redirected to LinkedIn's consent page, carrying the public client id and a random state
3 Browser palaestra.thrivetech.ai LinkedIn redirects back: GET https://palaestra.thrivetech.ai/api/auth/callback?code=…&state=…
4 Server api.linkedin.com Server-to-server over TLS. Exchanges code for an ID token. The browser is not involved.

The server then writes the player record and sets one session cookie.

Hop 3 returns to palaestra.thrivetech.ai, not to LinkedIn. A filter that permits palaestra.thrivetech.ai generally but blocks https://palaestra.thrivetech.ai/api/auth/callback will fail sign-in after the user has already authenticated with LinkedIn. The user sees a block page at the end of a successful login, which reads as the site being broken.

Both hosts must be reachable for sign-in to complete: palaestra.thrivetech.ai and www.linkedin.com from the browser, api.linkedin.com from the server.

Authentication and session

Property Value
Providers LinkedIn OpenID Connect. No others.
Passwords None exist. None is created, transmitted, stored, or recoverable.
Session token HMAC-SHA256 over an internal player id, keyed by a server-side secret
Verified Locally, by recomputing the signature. Not a bearer token for any third party.
Cookie flags HttpOnly, Secure, SameSite=Lax, Path=/
Lifetime 30 days
Revocation Sign-out deletes the cookie immediately

Authorization

Administrative access is a comma-separated allowlist of player ids in the deployment configuration, not a database column. It cannot be granted by anything the running application does, only by a deployment.

Administrative endpoints fail closed: an unauthorized caller receives 404, indistinguishable from a route that does not exist. A missing or empty allowlist grants nothing, including to the operator.

Secrets

SESSION_SECRET and LINKEDIN_CLIENT_SECRET are set through the deployment platform and appear in no file in either repository.

LINKEDIN_CLIENT_ID is public by construction; it travels in the address bar of every sign-in.

What executes in the browser

Static JavaScript, HTML and CSS served from the site's own origin. No plugin, extension, or local agent is required or offered. No file is downloaded. No file is uploaded. No user-supplied content is rendered to other users.

Unauthenticated endpoints

All on palaestra.thrivetech.ai.

Endpoint Limits
GET https://palaestra.thrivetech.ai/api/health None needed
GET https://palaestra.thrivetech.ai/api/scenarios Read-only catalogue
POST https://palaestra.thrivetech.ai/api/support Message ≤ 2000 chars, page ≤ 200 chars, attached trace ≤ 64 KB. Hard caps, enforced before any write.
GET https://palaestra.thrivetech.ai/api/unsubscribe/:token Signed token

Everything else requires a valid session and returns 403 without one.

Logging

The application writes structured error logs to the platform console. It writes no request log of its own.

Cloudflare Workers observability is enabled at full sampling. It records request method, path, status, ray id, and timing, under Cloudflare's retention.

Supply chain

Runtime dependencies are a small set of published npm packages: React, TanStack Router and Query, Hono, Observable Plot, and a markdown renderer. Dependabot is enabled. There is no vendored binary and no build-time network fetch beyond the package registry.

Verify

Copies of the running code:

Contact

support@palaestra.thrivetech.ai

See also Privacy Review.

Clone this wiki locally