// verified findings
Real bugs PullLight caught
in real open-source PRs
Every finding below is from a public scan you can verify. These are high and critical severity bugs PullLight found automatically — no manual triage, no curation.
// Each card links to the full scan result — diff, finding context, and AI explanation included.
30 verified findings
8 repos
high & critical only
vercel/eve
high
"`activeTurnId` is read by `toLifecycleEvent` before it is updated for `turn.started` events. On line 27, `toLifecycleEvent` is called with the old (undefined) `activeTurnId`, and only on line 28 is `a…"
logic
"`assert` from `node:assert/strict` throws an `AssertionError` (not a regular `Error`) when `response.ok` is false. The error message only includes the status code but not the response body, making it …"
error-handling
"The `LANGSMITH_API_KEY` is exposed to the browser bundle via Vite's `envPrefix` config. This is acknowledged in comments, but the `getApiKey()` function returns it unconditionally and it is passed dir…"
auth
"The `allowedIgnoredShellCommands` allowlist uses `allowedCommand.test(trimmedCommand)` with stateful `RegExp` objects. None of the three regexes use the `g` or `y` flag, so `lastIndex` is not an issue…"
logic
"Race condition / data inconsistency: `backend.edit` is called with `(filePath, content, repaired)` where `content` is the original file text read moments earlier. If another writer modifies the file b…"
logic
"`getApiKey()` returns `undefined` when `LANGSMITH_API_KEY` is not set, and `createManagedClient()` silently passes `{ apiKey: undefined }` to `ManagedClient`. This means all API calls (fetchThreads, c…"
auth
"The `timeout` timer is only cleared on the happy path (`clearTimeout(timeout)` after `await stdoutDone`). If `writeFile` throws, or if `spawn` throws, or if any `await` between the spawn and `clearTim…"
resource-leak
stripe/link-cli
high
"`nextRequestId` is a module-level mutable variable (`let nextRequestId = 1`). In environments where multiple `UcpResource` instances are used concurrently (e.g., multiple parallel requests), this shar…"
race-condition
supabase/sdk
high
"`d["components"]["schemas"]` is accessed without checking that `d["components"]` exists. If the generated OpenAPI file has no `components` key (e.g. for a minimal or malformed output), this will raise…"
null-deref
"When `vercelToken` is set, `source.type === 'vercel'` and the deployment ID is resolved via the Vercel API — but this entire block is only entered when `config.statusContext` is truthy. If a user supp…"
logic
"When `vercelToken` is set, `source.type === 'vercel'` but the outer guard is still `if (config.statusContext)`. This means if a user sets `vercel-token` but leaves `status-context` empty (or clears it…"
logic
vercel/eve
high
"The old code had an intentional early-exit `return []` after the first non-bot message with no files, which prevented scanning further back in the thread. The new code removes that guard and continues…"
logic
vercel/eve
high
"`timingSafeEqualStrings` short-circuits with `false` when the lengths differ, but this early-exit leaks the length of the expected secret via a timing side-channel. An attacker can binary-search the s…"
auth
"When `vercelToken` is set, the `source` is of type `'vercel'`, but the outer guard is still `if (config.statusContext)`. This means that if a user supplies `vercel-token` but leaves `status-context` e…"
logic
"When `vercelToken` is set but `statusContext` is empty, the `source` is built as `{ type: 'vercel', ... }` but the entire ID-resolution block is skipped because of the `if (config.statusContext)` guar…"
logic
stripe/link-cli
high
"`resolveCallback` is called at most once (on the first HTTP request), but the server is never closed after that first callback fires. Subsequent requests keep the server alive indefinitely. The caller…"
resource-leak
stripe/link-cli
high
"The `discoveryCache` and `negotiatedCache` are instance-level Maps, but `UcpResource` instances are created per-CLI-invocation (one per command run). This is fine for the CLI, but in the SDK the cache…"
auth
"When `vercelToken` is set, the `source.type` is `'vercel'` and the outer guard is `if (config.statusContext)`. This means `resolveDeploymentIdFromUrl` is only called when `statusContext` is non-empty.…"
logic
"When `vercelToken` is set, `source.type === 'vercel'` and the deployment ID is resolved via the Vercel API — but the outer guard is still `if (config.statusContext)`. This means that if a user supplie…"
logic
"When `vercelToken` is set, `source.type === 'vercel'` but the outer guard is still `if (config.statusContext)`. This means that if `statusContext` is empty (deployment-ID resolution disabled), the Ver…"
logic
"When `vercelToken` is set, `source.type === 'vercel'` but the outer guard is still `if (config.statusContext)`. This means if a user sets `vercel-token` but leaves `status-context` empty (or clears it…"
logic
"When `vercelToken` is set, the `source` is `{ type: 'vercel', ... }` and the guard is `if (config.statusContext)`. This means that if `statusContext` is empty (deployment ID resolution disabled), the …"
logic
stripe/link-cli
high
"The `message` string is interpolated directly into an HTML response without escaping: `res.end(`<html><body><p>${message}</p></body></html>`)`. Although `message` comes from the hardcoded `STATUS_MESS…"
injection
stripe/link-cli
high
"The `clientSecret` is passed as a plain string through CLI args (`--client-secret`) and stored in `UcpAuth`. When constructing the Basic auth header via `btoa('clientId:clientSecret')`, if `clientSecr…"
auth
vercel/eve
high
"When a concurrent duplicate-name error is caught and the sandbox is fetched via `getNamedVercelSandbox`, `requiresBaseRuntimeSetup` is set to `input.snapshotId === undefined`. This means the concurren…"
logic
"`assert(response.ok, ...)` throws an `AssertionError` (not a plain `Error`) when the Vercel API returns a non-2xx status. The error message includes only the status code, not the response body, making…"
error-handling
vercel/eve
high
"`namespaceHealthCache` is a module-level `Map` that stores `Promise<boolean>` values and is never evicted. In a long-running server process this means: (1) a failed probe result is cached forever — if…"
race-condition
axios/axios
critical
"**SSRF via fetch() with request-derived URL**: `const response = await fetch(req.body.callbackUrl)` passes a request-derived URL directly to an HTTP client. An attacker who controls this value can mak…"
injection
payloadcms/payload
high
"XSS via dangerouslySetInnerHTML — blockData.htmlContent is passed directly to dangerouslySetInnerHTML without DOMPurify sanitization. An attacker controlling this rich-text field value can inject scri…"
injection
"`getApiKey()` returns `undefined` when `LANGSMITH_API_KEY` is not set, and `createManagedClient()` silently passes `{ apiKey: undefined }` to `ManagedClient`. This means all API calls (fetchThreads, c…"
auth
// free for public repos
Install PullLight on your repo
Webhook fires on every PR. AI reviews the diff. You approve before anything posts. These are exactly the kinds of bugs it catches — automatically.