Skip to content

fix(security): harden linking, cache purges, ingest limits and secret checks - #21

Merged
masaok merged 1 commit into
mainfrom
security-hardening
Oct 4, 2026
Merged

masaok merged 1 commit into
mainfrom
security-hardening

Conversation

@masaok

@masaok masaok commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Why

A separate read-only agent reviewed the deployed code for authorization, ingest abuse, XSS and secrets. It found no cross-tenant access, SQL injection, stored XSS or committed secret. These six findings were real and cheap to close.

Scope

  • apps/web/src/lib/auth.ts: accountLinking no longer names trusted providers, so a link needs a provider-verified email. Before, an unverified address matching another user's could link into their account.
  • features/projects/actions.ts: updateProject, deleteProject and rotateApiToken call projectChanged only when the owner-scoped write matched a row. Before, a signed-in user could purge any site key's caches.
  • packages/core/src/directory.ts: past the lookup budget, ProjectDirectory.get returns the entry it already had. Before, a flood of junk keys made known projects resolve to unknown.
  • packages/core/src/ingest.ts: MAX_BODY_BYTES (8 KB) checked on Content-Length and on the text; hasBearer and safeEqual for constant-time secret checks, used by the Worker and /api/revalidate.
  • features/projects/queries.ts: cachedProject returns null for a malformed site key without a query or a cache entry.

Tradeoffs

Noted and left: a site key is public by design, so anyone can send fake pageviews for it and use up its daily cap; the project limit is check-then-insert; docker-compose.yml enables the demo login by default for the quickstart.

Verification

pnpm verify: 31 core, 28 ingest, 22 db, 8 web, 6 tracker, 2 next tests. New tests: an oversized body is not counted; a known project still counts after 40 junk keys spend the budget; hasBearer rejects a wrong, missing or unset secret.

https://claude.ai/code/session_01X2rqistoob3eewaQAJVwr3

… checks

From an independent review of the deployed code:
- accounts link across providers only on a provider-verified email
- project actions refresh caches only when the caller's row changed
- past the lookup budget, a known project keeps its last settings
- pageview bodies over 8 KB are ignored before parsing
- malformed site keys never reach the database or the cache
- bearer secrets are compared in constant time

Claude-Session: https://claude.ai/code/session_01X2rqistoob3eewaQAJVwr3
Copilot AI balanced review requested due to automatic review settings October 4, 2026 08:50
@vercel

vercel Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
copper-analytics Ready Ready Preview Oct 4, 2026 8:50am UTC

Request Review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@masaok
masaok merged commit 82a8a4f into main Oct 4, 2026
8 checks passed
@masaok
masaok deleted the security-hardening branch October 4, 2026 17:35

This branch was successfully deployed

1 active deployment
Preview — 0bf75555 Deployed Oct 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants