惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
C
Cisco Blogs
The Hacker News
The Hacker News
T
Tor Project blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
Vercel News
Vercel News
C
CERT Recently Published Vulnerability Notes
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
M
MIT News - Artificial intelligence
I
Intezer
aimingoo的专栏
aimingoo的专栏
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LINUX DO - 热门话题
Microsoft Security Blog
Microsoft Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
P
Proofpoint News Feed
B
Blog
T
Threat Research - Cisco Blogs
博客园 - 叶小钗
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
PCI Perspectives
PCI Perspectives
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
Application and Cybersecurity Blog
Application and Cybersecurity Blog
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Schneier on Security
Schneier on Security
N
News | PayPal Newsroom
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
博客园 - 聂微东
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Math.random() Is Not Secure. I Found It Generating API Keys in a 44K-Star Repo.
Ofri Peretz · 2026-05-30 · via DEV Community

The top Stack Overflow answer for "generate a unique token in JavaScript" returns this:

Math.random().toString(36).substring(2)

It appears in password reset tokens, session IDs, invite codes, and API keys across the JavaScript ecosystem. I found it verbatim in calcom/cal.diy (~44K stars) — the MIT open-source edition of Cal.com:

const apiKey = `cal_live_${Math.random().toString(36).substring(2)}`;

Math.random() is a PRNG, not a CSPRNG. An attacker who observes consecutive outputs from a server-side process can recover the internal state and predict every future token. Here is the attack, the ESLint rule that catches this pattern automatically, and the one-line fix.


Why Math.random() is dangerous for tokens

Math.random() is a pseudo-random number generator — fast, but deterministic. Given V8's initial seed, its entire output sequence is fixed. An attacker who observes enough outputs can recover the 128-bit internal state and predict every future call.

// What you write:
const token = Math.random().toString(36).substring(2);

// V8 uses xorshift128+ under the hood.
// After observing a handful of consecutive Math.random() calls from the same process:
// → internal state recoverable (see d0nutptr/v8_rand_buster)
// → all future Math.random() outputs predictable
// → all future tokens predictable

CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator.

The exploit

xorshift128+ is algebraically invertible. Given full-precision doubles (52 bits each), the 128-bit internal state can be recovered. The v8_rand_buster implementation recovers state from 3–4 consecutive Math.random() outputs. The following shows the attack flow — the concrete values are illustrative; v8_rand_buster handles the actual algebra.

// Illustrative pseudocode — attacker collects consecutive Math.random() outputs:
//   cal_live_k7f2m9p8x3z  →  Math.random() returned 0.38914728471823...
//   cal_live_hq5r1n6wzt   →  Math.random() returned 0.72342901847612...
//   cal_live_p9x4b2m7vy   →  Math.random() returned 0.15678234019876...

// Feed full-precision doubles to state-recovery:
// → internal xorshift128+ state reconstructed (s0, s1 recovered algebraically)

// Predict the next Math.random() call:
// → 0.59123847561029...  →  "cal_live_s2v8n3k1xq"
// Attacker knows the next key before it is issued.

xorshift128+ is algebraically invertible: given output values (full 52-bit precision), the 128-bit internal state can be solved. v8_rand_buster recovers state from 3–4 consecutive outputs. The practical requirement is consecutive outputs from the same process — which is achievable when key generation is observable and isolated.

Two attack surfaces, depending on where the code runs:

Client-side (the calcom/cal.diy case): The key is generated in the user's own browser. Client-side key generation exposes the credential in the client's environment before it reaches the server — visible in network logs, browser devtools, extensions, or XSS. The PRNG weakness is secondary to the architectural problem of minting a secret in the browser at all.

Server-side (the more general case): If Math.random() generates tokens in a server process, an attacker who observes multiple consecutive tokens (e.g., via multiple signups, password resets, or API requests) can recover internal state and predict the next token — including tokens for other users. This is the scenario where state recovery attacks apply most cleanly.


Where this pattern appears

// Top Stack Overflow pattern for "generate unique token":
const token = Math.random().toString(36).substring(2, 15);

// Session ID (with Date.now() — adds a predictable timestamp, not additional unpredictability):
const sessionId = Date.now().toString(36) + Math.random().toString(36).substring(2);

// Invite code:
const inviteToken = Math.random().toString(36).substring(2, 8).toUpperCase();

// The calcom/cal.diy pattern:
const apiKey = `cal_live_${Math.random().toString(36).substring(2)}`;

The first three are less exploitable than the calcom/cal.diy pattern — partial substrings leak less state per observation. But all four use a PRNG for a value that should be a CSPRNG.


Why it survives code review

  • Math.random() literally has "random" in the name
  • The output looks unpredictable: k7f2m9p8x3z
  • No runtime errors — tokens generate correctly, tests pass
  • Reviewers focus on the business logic, not PRNG security properties

Nobody reviews token generation and asks "is this the right kind of random?" The ESLint rule asks it for you.

Source context: calcom/cal.diy is the MIT open-source edition of Cal.com (the enterprise codebase runs separately under AGPL as calcom/cal.com). The Math.random() line is in a client-side React component. For client-side code, the architectural problem — generating a secret in the browser — is the primary concern. The PRNG weakness is secondary, but it compounds. The state-recovery attack in the Exploit section applies directly to server-side equivalents of this pattern.


The ESLint rule that catches it

eslint-plugin-node-security/no-math-random-crypto fires when Math.random() is assigned to a variable whose name matches any of 18+ security-sensitive patterns: token, key, secret, session, auth, csrf, nonce, otp, code, verify, and more.

On false positives: React's list reconciliation key prop doesn't trigger this — the rule checks Math.random() assignments, not JSX attributes. code for HTTP status codes or country codes won't trigger either, because the rule only fires when Math.random() is the value being assigned. If you have legitimate non-security uses of a key variable fed by Math.random() (rare but possible), configure allowInTests: true or use an ESLint disable comment with a note explaining why.

node-security/no-math-random-crypto
CWE-338 | Math.random() used in cryptographic context 'apiKey'
Use crypto.randomBytes() or crypto.randomUUID() instead
  apps/web/components/apps/make/Setup.tsx (line varies by version)

This fires on the calcom/cal.diy line.


The fix — server-side vs client-side

Server-side (Node.js API route, Express, NestJS):

import crypto from 'node:crypto';

// Opaque token — hex string, 48 characters:
const apiKey = `cal_live_${crypto.randomBytes(24).toString('hex')}`;

// UUID format:
const id = crypto.randomUUID();

Client-side / browser (the deeper issue in the calcom/cal.diy case):

Generating secret API keys client-side is itself the architectural problem — the key is visible in client memory and potentially in browser devtools. The right fix is to move key generation server-side and return the key via an authenticated API call. If you must generate randomness in the browser, use Web Crypto:

// Web Crypto — available in all modern browsers and Node.js 19+:
const array = new Uint8Array(24);
globalThis.crypto.getRandomValues(array);
const token = Array.from(array).map(b => b.toString(16).padStart(2, '0')).join('');

globalThis.crypto.getRandomValues() uses the OS CSPRNG and is safe in both browser and Node.js environments.


The config

// eslint.config.mjs
import nodeSecurity from 'eslint-plugin-node-security';
import tsParser from '@typescript-eslint/parser';

export default [
  {
    files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
    languageOptions: { parser: tsParser },
    plugins: { 'node-security': nodeSecurity },
    rules: {
      'node-security/no-math-random-crypto': 'error',
    },
  },
];

npm install --save-dev eslint-plugin-node-security
npx eslint src/

Full rule documentation at eslint.interlace.tools.

Note: this rule catches the PRNG problem. It won't flag client-side key generation as an architectural issue — that's a separate concern for code review.

If you're auditing older code for this class of vulnerability more broadly, the 30-minute security audit protocol covers Math.random() alongside credential handling, JWT configuration, and input validation in a single pass.


Have you run this against your codebase yet? I'm specifically curious where it shows up — expected places like token generation, or somewhere that surprised you.


Part of the Exploit Analysis series. See also:
Exploit Analysis: The JWT Algorithm 'none' Attack (And the Guard)


📦 eslint-plugin-node-security · Rule docs

⭐ Star on GitHub


GitHub | X | LinkedIn | Dev.to | ofriperetz.dev