Repository navigation
Conversation
Run osv-scanner during setup, persist the result to osv-findings.json, and inject a summary of known-vulnerable dependencies into the threat-model prompt so the model writes the Threat model and patterns-to-flag sections with those advisories in view (and reasons about whether each is reachable, not just present). - osv-enrich.ts: run osv-scanner, parse results, drop vendored sources (.deepsec/node_modules/vendor), keep each advisory's id + one-line summary so the ids are self-explanatory, and write osv-findings.json as a first-class artifact. - repository-analysis.ts: optional dependencyContext appended to the threat-model prompt. - coordinator.ts: run osv before the info phase and pass the context through. Degrades cleanly when osv-scanner is absent or finds no package sources. Hermetic tests cover parsing, vendored-source filtering, summaries, and prompt injection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ning osv-scanner only reads pinned lockfiles, so a source package that declares dependency ranges in a manifest (no lockfile) reports "no package sources" and every dependency CVE is missed. Resolve the manifest to its lowest allowed versions — the worst-case / applicable-CVE floor, since a `>=` constraint permits a build to land on that floor — with `uv pip compile --resolution lowest`, then hand osv-scanner the resolved lockfile alongside the recursive source walk. The resolved lockfile is written to a temp dir (so its osv source path is not treated as vendored) and a copy is kept as deps-lowest.txt evidence next to osv-findings.json. Degrades cleanly: when uv is missing or the manifest cannot be resolved, the scan falls back to the source walk unchanged. On a bare pyproject.toml (fastapi, range-only) this surfaces 22 advisories across anyio/idna/starlette where the source walk alone found none. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ories (phase 2) Phase 1 fed dependency CVEs into the threat model, which shapes the per-finding investigation. But matcher generation — the step that decides which code even becomes a scan candidate — only ever filled surface-coverage gaps; it never saw the CVEs. So a dependency advisory was only surfaced when its code happened to also be an uncovered surface (incidental), and a CVE in already-covered or non-surface code was never flagged at all. Pass the threat model (INFO.md) and the known-vulnerable dependency count into proposeMatchers. When the project has vulnerable deps, the prompt asks the agent to also propose matchers anchored to the reachable advisories' call sites (e.g. a form-parsing call with no size/field limit), skipping the ones the threat model marks not-reachable. The coordinator runs one matcher pass even when every surface is already covered, so a dependency CVE in non-gap code still gets a matcher. Degrades cleanly: no vulnerable deps or no threat model → unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@Nehanth is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
🤖 auto-maintain reviewAutomated, advisory triage for
Review panel: 🔴 high highest severity deepsec maintainer code review: 🟡 medium
General code review: 🟡 medium
Scanner and matcher quality: 🔴 high
Sandbox and credential boundaries: 🟡 medium
Durability and distributed state: 🟡 medium
Posted by auto-maintain. This automated code review is advisory; a human maintainer makes the call. |
| maxBuffer: 64 * 1024 * 1024, | ||
| stdio: ["ignore", "pipe", "ignore"], | ||
| }); | ||
| } catch (error) { | ||
| const stdout = (error as { stdout?: unknown })?.stdout; |
…kpoints) Addresses the automated review on the dependency-CVE adapter: Security: - uv is now sandboxed when resolving a repo-controlled manifest: `--no-build` (no PEP 517 build hooks / dynamic-metadata project builds), `--no-sources` (ignore attacker `[tool.uv.sources]`), and an empty temp cwd (no project `uv.toml`/`[tool.uv]`). Resolution still works; repo code never executes. - Sanitize package name/version (collapse whitespace, clamp length) before they reach the threat-model prompt — blocks newline/markdown injection from attacker-controlled lockfile fields. - osv-scanner now runs with a timeout (it had none) so a stalled scan can't wedge the info phase indefinitely. - Probe for uv/osv-scanner on PATH; a missing tool is reported distinctly (warn, no artifact) instead of writing an empty osv-findings.json that reads as "no vulnerable dependencies". Correctness: - Skip floor resolution when an authoritative lockfile exists (uv.lock, poetry.lock, requirements.txt, …) so installed/patched versions aren't overridden by hypothetical floor versions (false positives). - Resolve both lowest and highest allowed versions (widens range coverage). - Resolve every manifest in a monorepo, not just the first. - Dedupe parseOsv by name@version@ecosystem (a package can surface from multiple resolved lockfiles). - Matcher prompt: require closesSurfaceIds (the schema rejects empty, which could abort setup) — point it at the surface the vulnerable call sits in. Checkpoints / durability: - Bump rubricVersion (2 -> 3) so existing projects re-run and gain the enrichment. - Don't restore the pre-osv INFO.md over the CVE-enriched threat model. - Run the dependency-CVE matcher pass only on first generation, not every resume. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d on vercel-labs#190) osv-scanner can't read a bare pom.xml. syft resolves the Maven project into a CycloneDX SBOM, which osv-scanner then matches against advisories (reusing our osv tool, not grype). syft is probed on PATH and run with a timeout; it only catalogs (no build/exec). parseOsv dedup already merges a package seen from both osv's pom parse and the SBOM. Stacked on vercel-labs#190 (the Python osv adapter + hardening); this commit is the Java addition on top. Validated end-to-end on WebGoat (xstream 1.4.5 -> 36 advisories, SBOM resolved, CVE-targeted matcher generated). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-positives
Addresses the second review pass:
Security:
- Reject manifests with PEP 508 direct URL/VCS/path deps before resolving — uv
would otherwise fetch attacker-chosen URLs (SSRF). (`--no-sources` only covered
`[tool.uv.sources]`.)
- Write resolver evidence AND osv-findings.json under the gitignored `data/<id>/
setup/` dir so they are never committed/pushed to the shared data repo (a
compiled index URL could carry a private-index token).
Failure handling (no silent false negatives):
- Distinguish a real scan failure (timeout/crash/no parseable output) from a
clean/no-sources scan: on failure, warn and do NOT overwrite osv-findings.json
with an empty result (which would erase prior findings / read as "no vulns").
- Warn when uv is missing but range-only manifests exist (same treatment as a
missing osv-scanner).
False positives / correctness:
- Mark resolved floor/ceiling versions as hypothetical ("resolved range version —
not necessarily installed") in the threat-model context, so an up-to-date
project isn't reported as actually vulnerable.
- Drop requirements.txt from the authoritative-lockfile list (it is often
unpinned, which would wrongly skip resolution).
Durability / cancellation:
- Track the dependency-CVE matcher pass with its own state flag
(`osvMatcherPassDone`) instead of matcherAttempts length — so it runs once, and
upgraded projects with older matcher attempts still get it after rubricVersion 3.
- Cap resolved manifests (10) and add an overall resolve-time budget so a large
monorepo can't stall setup for many minutes (the sync calls can't observe an
abort signal; bounding total time is the pragmatic guard — full async
cancellation is a follow-up).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The round-2 INFO.md merge appended the fresh osv advisory section to the prior INFO.md, but that file already contained a previously appended section — so refreshes accumulated duplicate sections and kept listing dependencies that had since been patched or removed (false positives). Extract mergeInfoWithOsvContext(): strip any previously appended section (located by the shared OSV_CONTEXT_HEADING) before appending the current one, and drop the section entirely when there are no current advisories. Curated content is kept. (The related "upgraded projects never get the CVE matcher pass when coverage passes" finding was already addressed by the osvMatcherPassDone checkpoint flag.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The osv step runs external, network-reaching tools (osv-scanner, uv, syft) during setup, which crosses the documented read-only/no-network analysis boundary. Make it opt-in per project: `osv: true` in the deepsec.config.ts project declaration. Off by default — when unset, runOsvEnrich is never called (no network, no overhead). Enabling it (osv: true) invalidates only that project's info checkpoint via the digest, forcing one re-run to adopt the enrichment; projects that never enable it keep their prior digest and are not re-run. hasDepCves is also gated on the flag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enable dependency-CVE enrichment per run with deepsec setup/init --osv, alongside osv: true in deepsec.config.ts. Default off. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add docs/dependency-cves.md (what it does, --osv flag / osv:true config, required tools, Python ranges + Java/Maven coverage, how results surface, security notes, limitations). Add the `osv` field to the ProjectDeclaration reference, list the page in the docs nav, and note the dependency step as the opt-in exception to the read-only/no-network analysis boundary in vercel-setup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the dependency-CVE path deterministic at the two steps where it was silently losing reachable advisories to run-to-run variance. - threat model: buildContext now emits a required, graded "Dependency reachability" block — one line per dependency (HIGH/MEDIUM/LOW + call site + consequence), covering every advisory osv found, instead of a soft "note where it's used" prose instruction that collapsed into a vague summary on noisier runs. - investigation: CORE_PROMPT now treats those grades as promotion guidance — HIGH with a confirmed call site is a finding to promote (not "just a library default"), MEDIUM is judged on its merits, LOW stays as context unless a missed call site is found. Reachability is gated upstream; the investigation confirms and writes it up. Verified on fastapi: the Starlette unbounded-body DoS now promotes to a located finding (dropped as context in prior runs), while transitive anyio/idna stay LOW with zero false-positive findings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…isting INFO.md When osv was enabled on a project that already had a complete INFO.md, the preserve path overwrote the freshly generated analysis with the old threat model plus osvEnrichment.context. Since that context is now a prompt directive (instructions to emit a graded Dependency reachability block), the persisted INFO.md ended up carrying raw grading instructions and the real verdicts the analysis agent just produced were discarded — so matcher generation saw the stale threat model, not the reachability grades. Enabling osv is a deliberate "re-analyze with dependencies in view" action, so keep the fresh analysis (verdicts included) instead of restoring the preserved copy. The non-osv preserve path is unchanged and still keeps curated content. Adds a coordinator test for the osv + preserved-INFO.md path (verified to fail without the fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Setup state and INFO.md handling: - Remember the last explicit --osv / --no-osv choice in setup state, and carry --osv in the printed resume command. Previously a plain resume or a later bare init/setup flipped the info checkpoint digest, re-ran the analysis without dependency context, and dropped the reachability verdicts. --no-osv is new and is the way to turn the step back off. - Keep a hand-edited INFO.md on every re-run. Only the agent's "### Dependency reachability" block is refreshed (spliced into the Threat model section), kept as-is when osv produced nothing, and removed when osv is off. - Stop the osv section strip at the next "## " heading instead of cutting to end of file. - Record the dependency matcher pass only after it completes, keyed to a digest of the vulnerable-dependency set, so a failed pass is retried and a newly found dependency gets its own pass. - Ignore a leftover osv-findings.json when osv is disabled. Scanning: - Resolve ranges with --resolution lowest-direct instead of lowest, so only declared dependencies are floored. Plain lowest also pinned transitive dependencies to versions no real install picks; on fastapi this cut the report from 3 packages / 22 advisories to starlette / 14. - Capture osv-scanner stderr so "No package sources found" (exit 128, empty stdout) is treated as a clean result and clears stale findings. - Match vendored trees against the path relative to the project root, so a project checked out under a vendor/ directory is not filtered out. - Warn when uv or syft fails to resolve a manifest instead of reporting it as clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| const merged = osvEnabled | ||
| ? freshBlock | ||
| ? spliceReachabilityBlock(curated, freshBlock) | ||
| : curated | ||
| : spliceReachabilityBlock(curated, undefined); |
What
Adds an osv-based dependency-CVE step to setup so known-vulnerable dependencies are surfaced, reasoned about for reachability, and turned into located findings — not just listed. Covers Python (pyproject ranges) and Java/Maven (pom.xml).
osv-findings.json, and inject a "Known-vulnerable dependencies" section into the repository-analysis prompt so the agent judges reachability per advisory.pyproject.tomlreports "no package sources". Resolve lowest+highest allowed versions withuv pip compileand hand osv the resolved lockfiles.pom.xml;syftresolves the Maven project into a CycloneDX SBOM that osv then matches (reuses osv, not grype).Security & robustness hardening (per review)
--no-build,--no-sources, isolated cwd (no arbitrary code execution).parseOsvdedup.Validation (end-to-end)
pyproject): 0 → 22 advisories floor-resolved; produced a located Starlette multipart-DoS finding the baseline never generates.xstream 1.4.5):syft→SBOM→osv surfaced 36 advisories; matcher steering generatedxstream-fromxml-deserialization.Degrades cleanly throughout: missing tool, no vulnerable deps, or no manifest → empty context, setup unchanged.
(The Java work was briefly opened as a stacked PR #191; folded into this PR instead — one combined adapter.)
🤖 Generated with Claude Code