Summary
The email tracking pixel endpoint (/p/:blob.gif) has no rate limiting, allowing enumeration attacks and resource abuse. The bot detection mechanism relies solely on User-Agent string matching and timing heuristics, which are trivially bypassed.
Affected Files
internal/tracking/worker/src/index.ts (lines 40-97)
internal/tracking/worker/src/bot.ts
Current Code
index.ts — No rate limiting on pixel endpoint:
async function handlePixel(request: Request, env: Env, path: string): Promise<Response> {
const blob = path.slice(3, -4);
const key = await importKey(env.TRACKING_KEY);
// ... decrypts and records open with no rate check
// Every request hits D1 database INSERT
}
bot.ts — Detection based on User-Agent strings only:
export function detectBot(userAgent: string, ip: string, timeSinceDeliveryMs: number | null): BotDetectionResult {
if (userAgent.includes('GoogleImageProxy')) return { isBot: false, botType: 'gmail_proxy' };
if (userAgent.includes('Outlook-iOS') || userAgent.includes('Microsoft Outlook')) return { isBot: true, botType: 'outlook_prefetch' };
if (userAgent.includes('Barracuda') || userAgent.includes('Symantec') || userAgent.includes('Proofpoint')) return { isBot: true, botType: 'security_scanner' };
// Trivially bypassed by setting any other User-Agent
return { isBot: false, botType: null };
}
Risk
- Tracking ID enumeration: An attacker can brute-force or replay tracking pixel URLs to inflate open counts, polluting analytics
- D1 database abuse: Each pixel request triggers a D1 INSERT — no deduplication means repeated requests fill the database
- Resource exhaustion: High-volume requests against the worker endpoint consume Cloudflare Workers resources
- Bot detection bypass: Setting
User-Agent: Mozilla/5.0 bypasses all bot detection
Remediation
-
Add Cloudflare Rate Limiting via wrangler.toml:
# Or use the Rate Limiting API in the worker
-
Deduplicate opens — Only record the first open per tracking_id per IP within a time window:
const existing = await env.DB.prepare(
'SELECT 1 FROM opens WHERE tracking_id = ? AND ip = ? AND opened_at > datetime("now", "-1 hour")'
).bind(blob, ip).first();
if (existing) return pixelResponse(); // Already recorded
-
Add IP-based rate limiting using Cloudflare's request.cf or a KV-based counter:
const rateKey = `rate:${ip}`;
const count = parseInt(await env.RATE_KV.get(rateKey) || '0');
if (count > 100) return pixelResponse(); // Silent rate limit
await env.RATE_KV.put(rateKey, String(count + 1), { expirationTtl: 3600 });
-
Improve bot detection — Consider checking for:
- Missing or suspicious headers (no
Accept, no Referer)
- Known datacenter IP ranges
- TLS fingerprinting (via Cloudflare Bot Management if available)
Summary
The email tracking pixel endpoint (
/p/:blob.gif) has no rate limiting, allowing enumeration attacks and resource abuse. The bot detection mechanism relies solely on User-Agent string matching and timing heuristics, which are trivially bypassed.Affected Files
internal/tracking/worker/src/index.ts(lines 40-97)internal/tracking/worker/src/bot.tsCurrent Code
index.ts — No rate limiting on pixel endpoint:
bot.ts — Detection based on User-Agent strings only:
Risk
User-Agent: Mozilla/5.0bypasses all bot detectionRemediation
Add Cloudflare Rate Limiting via
wrangler.toml:# Or use the Rate Limiting API in the workerDeduplicate opens — Only record the first open per tracking_id per IP within a time window:
Add IP-based rate limiting using Cloudflare's
request.cfor a KV-based counter:Improve bot detection — Consider checking for:
Accept, noReferer)