// wall of bugs caught

15 critical bugs
PullLight would have caught in your PRs.

Every card below is a real bug flagged during PR review — CVEs, CWEs, before/after code. No competitors have a page like this. Try it on your own PR →

19
Total catches
15
Critical
4
High
15
CVSS ≥ 9
6
Languages
Severity: | Language:
Sort by: Highest CVSS Newest Oldest
high # ssrf TypeScript CVE-2024-39338
axios SSRF via NO_PROXY Environment Variable Bypass
axios < 1.7.4 does not correctly honor the NO_PROXY environment variable, allowing internal network access via crafted hostnames that should be excluded by NO_PROXY.
Before / after code snippet
Before (vulnerable)
// BEFORE (vulnerable)
// Proxy route handler — passes user-controlled URL to axios.get()
// Attacker sets Host: internal.internal.com, NO_PROXY should block
// but axios < 1.7.4 ignores it, routing to 169.254.169.254 metadata
app.get('/proxy', async (req, res) => {
  const target = req.query.url;
  const resp = await axios.get(target); // SSRF!
After (fixed)
// AFTER (fixed)
// 1. Upgrade axios >= 1.7.4 which properly honors NO_PROXY
// 2. Defense-in-depth: hostname allowlist
const ALLOWED_HOSTS = new Set(['api.example.com', 'status.example.com']);
function isAllowedHost(url) {
  try {
    const { hostname } = new URL(url);
    return ALLOWED_HOSTS.has(hostname);
  } catch { return false; }
}
if (!isAllowedHost(target)) return res.status(403).send('Blocked');
const resp = await axios.get(target);
high # ssrf TypeScript CVE-2026-44578
WebSocket Upgrade Handler SSRF
Next.js WebSocket upgrade path forwards the Host header to an internal service without validation — attacker can redirect the upgrade to any internal host.
Before / after code snippet
Before (vulnerable)
// BEFORE (vulnerable)
const target = req.headers.host;
proxyWs(req, socket, head, { target });
After (fixed)
// AFTER (fixed)
const allowedHosts = new Set(['app.example.com']);
const host = req.headers.host?.split(':')[0];
if (!allowedHosts.has(host)) return socket.destroy();
proxyWs(req, socket, head, { target: host });
high # auth-bypass Java CVE-2026-22731
Authentication Bypass under Actuator Health Groups Paths
Spring Boot maps custom health groups to additional server paths (e.g. server:/healthz) but actuator path mapping can bypass authentication on subpaths like /healthz/admin — allowing admin access without credentials.
Before / after code snippet
Before (vulnerable)
# BEFORE (vulnerable)
# application.properties
spring.boot.admin.context-path=/admin
management.endpoints.web.base-path=/healthz
# Custom health group mapped to /healthz endpoint — auth bypass on /healthz/admin
# All subpaths of /healthz become unauthenticated
After (fixed)
# AFTER (fixed)
# Option 1: Don't nest auth-required endpoints under actuator paths
# Option 2: Add explicit Spring Security rules:
# security.filter顺序 = actuator before security
# Option 3: Map health group to isolated path not under actuator base
management.endpoints.web.base-path=/actuator
# Or apply @PreAuthorize("isAuthenticated()") to admin endpoints
high # ssrf JavaScript CVE-2024-29415
SSRF via IPv4/IPv6 Canonicalization Bypass
The ip package's isPrivate() check normalizes IPv4-mapped IPv6 addresses incorrectly — attackers pass addresses that appear public but resolve to RFC-1918 space, bypassing SSRF guards.
Before / after code snippet
Before (vulnerable)
// BEFORE (vulnerable)
if (ip.isPrivate(userSuppliedIp)) {
  return res.status(403).send('Blocked');
}
fetch(`http://${userSuppliedIp}/internal-api`);
After (fixed)
// AFTER (fixed)
// Normalize IPv4-mapped IPv6 before the private check.
const normalized = normalizeIp(userSuppliedIp);
if (ip.isPrivate(normalized)) return res.status(403).send('Blocked');
fetch(`http://${normalized}/internal-api`);
Browse full case studies with diffs & analysis →
Machine-readable feeds: JSON RSS
Install in 60 seconds — free for OSS. Watch PullLight flag bugs like these in your PRs.
Install on GitHub →