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

  1. Browser requests /api/auth/login. Server redirects to LinkedIn with the public client id, a redirect URI, and a random state.
  2. LinkedIn authenticates the user and redirects to /api/auth/callback?code=…&state=….
  3. Server validates state, then exchanges code for an ID token over TLS to api.linkedin.com.
  4. Server writes the player record and sets one session cookie.

A filter that permits the domain but blocks /api/auth/callback will fail sign-in after the user has already authenticated.

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

Endpoint Limits
GET /api/health None needed
GET /api/scenarios Read-only catalogue
POST /api/support Message ≤ 2000 chars, page ≤ 200 chars, attached trace ≤ 64 KB. Hard caps, enforced before any write.
GET /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