Tech & Random Stuff

CSPRNG Anti-Detection: Making Automated Browser Actions Undetectable

How to use cryptographically secure random number generators with human-like distributions to make browser automation invisible to anti-bot systems.

2026-06-18·12 min read

Anti-bot detection systems analyze behavioral patterns to distinguish humans from automation. The most common tell is timing — Math.random()-based delays create detectable patterns. This guide covers how CSPRNG with human-matched distributions defeats these systems.

Why Math.random() Gets You Caught

JavaScript's Math.random() uses a xorshift128+ PRNG with a deterministic, predictable state. From just a few outputs, the entire sequence can be reconstructed. Anti-bot systems use this to detect automation:

  • Math.random() produces a deterministic sequence — predictable from outputs
  • Uniform distribution is unnatural — humans don't act with even timing
  • No long-tail behavior — humans have occasional very long pauses
  • No correlation between actions — human delays correlate with task complexity

CSPRNG: Cryptographically Secure Alternative

crypto.randomBytes() uses the OS entropy pool (CryptGenRandom on Windows, /dev/urandom on Linux). This produces truly unpredictable output that cannot be reconstructed or correlated:

// CSPRNG with 4096-byte buffer for efficiency
const crypto = require('crypto');
const BUF_SIZE = 4096;
let buf = crypto.randomBytes(BUF_SIZE);
let bufOffset = 0;

function cryptoRandom(): number {
  if (bufOffset + 8 > BUF_SIZE) {
    buf = crypto.randomBytes(BUF_SIZE);
    bufOffset = 0;
  }
  const hi = buf.readUInt32BE(bufOffset);
  const lo = buf.readUInt32BE(bufOffset + 4);
  bufOffset += 8;
  return (((hi >>> 5) * 0x4000000 + (lo >>> 6)) / 0x20000000000000);
}

Human-Matched Distributions

The key insight is that humans don't act with uniform timing. Real human behavior follows specific statistical distributions. By matching these, automation becomes indistinguishable from human input.

DistributionUse CaseCharacteristicsPercentage
TriangularFast actions (clicks, quick typing)Peaked at 30% of range — most actions are fast70%
Gaussian (Normal)Normal actions (navigation, reading)Bell curve around midpoint25%
ExponentialLong pauses (thinking, distracted)Long-tail — occasional very long delays5%

Implementing Human Delay

The human delay function combines all three distributions to create natural timing patterns:

function humanDelayRng(min: number, max: number): number {
  const r = cryptoRandom();
  if (r < 0.70) {
    // 70%: Triangular peaked at 30% of range (fast actions)
    const mode = min + (max - min) * 0.3;
    return clamp(triangular(min, mode, max), min, max);
  } else if (r < 0.95) {
    // 25%: Gaussian around midpoint
    const mid = (min + max) / 2;
    const std = (max - min) * 0.2;
    return clamp(gaussian(mid, std), min, max);
  } else {
    // 5%: Exponential tail (long thinking pauses)
    const rate = 1 / ((max - min) * 0.3);
    return clamp(min + exponential(rate), min, max * 1.5);
  }
}

Typing Delays: Log-Normal Distribution

Human typing follows a log-normal distribution — most keystrokes are fast with occasional slow ones. This is the most critical distribution for detection:

function typingDelay(): number {
  // Log-normal: most keystrokes fast, occasional slow ones
  const base = logNormal(60, 0.4); // mean=60ms, sigma=0.4
  return Math.max(20, Math.min(200, Math.round(base)));
}

⚠ WarningTyping too fast (sub-20ms per keystroke) or too uniformly (all keystrokes within 5ms of each other) is the #1 detection signal for anti-bot systems.

Mouse Movement: Bezier Curves with Jitter

Humans don't move the mouse in straight lines. They follow curved paths with micro-jitters. Implement this with bezier curves and gaussian jitter:

async function humanMouseMove(page, targetX, targetY) {
  const startX = cryptoInt(0, 1920);
  const startY = cryptoInt(0, 1080);
  const steps = cryptoInt(18, 35); // variable step count
  
  for (let i = 0; i <= steps; i++) {
    const t = i / steps;
    const easeT = t * (2 - t); // ease-out
    const jitterX = gaussian(0, 10); // micro-jitter
    const jitterY = gaussian(0, 10);
    const x = startX + (targetX - startX) * easeT + jitterX;
    const y = startY + (targetY - startY) * easeT + jitterY;
    await page.mouse.move(x, y);
    await wait(10 + cryptoRandom() * 20); // variable step delay
  }
}

Click Position: Not Centered

Automation tools click the exact center of elements. Humans click slightly off-center. Randomize click position within element bounds:

function clickOffset(): number {
  // Click at 30-70% of element bounds, not center
  return 0.3 + cryptoRandom() * 0.4;
}

Putting It All Together

The automation project combines all these techniques into a complete anti-detection system. The visual test page shows the CSPRNG keyboard and mouse behavior in real-time.

  • CSPRNG for all random values (crypto.randomBytes, 4096-byte buffer)
  • Triangular/Gaussian/Exponential distribution mix for delays
  • Log-normal distribution for typing delays
  • Bezier curves with gaussian jitter for mouse movement
  • Off-center click positions (30-70% of element bounds)
  • Variable mouse step count (18-35 steps)
  • Human-like scroll amounts with natural variation
  • Occasional long breaks (exponential tail) during repetitive tasks

✦ TipThe combination of CSPRNG + human-matched distributions + bezier mouse movement makes automation statistically indistinguishable from human behavior. Anti-bot systems cannot detect the difference.

← All tutorialsTech & Random Stuff