Skip to content

Use a cryptographic random source for new document slugs #442

Description

@HMarzban

Summary

A new document's slug comes from Math.random(), which is not a cryptographic source. Its output can be predicted. The first signed-in focus or edit on an ownerless document claims ownership (CONTEXT.md §Document access, Open document). So someone who predicts a fresh slug can open it first and own another person's new document.

  • Severity: Low
  • Area: webapp document creation
  • Source: security review of 2026-10-06, finding L5

Where

  • apps/webapp/src/utils/sanitizeDocumentSlug.ts:9 — (Math.random() + 1).toString(36).substring(2).
  • apps/webapp/src/proxy.ts:13 — the same expression for the new. host redirect.
  • apps/webapp/src/proxy.ts:36 also uses Math.random(), for log sampling only. Leave it.

Constraint

Root CLAUDE.md §Settled (Next product APIs) says "Do not edit src/proxy.ts". Changing line 13 needs maintainer approval. If refused, change sanitizeDocumentSlug.ts only and have proxy.ts import that helper in a later approved change.

Fix plan

  1. In sanitizeDocumentSlug.ts, build the random slug from crypto.getRandomValues (available in the browser, in Bun and in the Next.js edge runtime). Keep the same alphabet (0-9a-z) and a length of at least 11 characters.
  2. With approval, make proxy.ts:13 call the same helper instead of repeating the expression.

Acceptance criteria

  • No slug generator uses Math.random().
  • New slugs keep the current format, and /new and the new. host still open a fresh document.

Verify

  • grep -rn "Math.random" apps/webapp/src/utils/sanitizeDocumentSlug.ts apps/webapp/src/proxy.ts shows only the log-sampling line.
  • Open /new twice and check two different slugs of the expected length.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    SecuritySecurity, access control, and data exposurebugSomething isn't working

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions