# Dependency Vulnerability Scanner with OSV Data

> Dependency vulnerability scanner for npm, PyPI, Maven, Go, Cargo and more via OSV.dev. Paste a lockfile and get one row per CVE with the fix version.

URL: https://cliqtomedia.com/actors/osv-dependency-vulnerability-scanner/

Category: Developer & website monitoring · Status: coming soon · Apify profile: https://apify.com/cliqtomedia?fpr=cliqto

Paste a package list, package.json, package-lock.json or requirements.txt. You get one row per known vulnerability with severity and CVSS. It also shows the fix version for your branch.

## How to use it: 3 steps

1. **Follow us on Apify.** The tool is built and waits in the queue for the Apify Store. Apify is the cloud platform where our tools run.
2. **Paste your input and press Start.** No code needed: you fill in a form (the input). It already has a working example. For example: `npm:lodash@4.17.15` in Dependencies (ecosystem:name@version). Each start is one run.
3. **Download the results.** When the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

## What it does

Dependency Vulnerability Scanner checks your npm, PyPI, Maven, Go, Cargo and other packages for known vulnerabilities in the free [OSV.dev](https://osv.dev) database. Paste a list such as `npm:lodash@4.17.15`, a `package.json`, a `package-lock.json` or a `requirements.txt`. You get one row per vulnerability with the CVE and GHSA ids, severity, CVSS score, CWE and the version that fixes it on **your** version branch.

- Reads your input. A list, a manifest or a lockfile. Duplicates are checked once. A line it cannot check (no version, a git URL, an unsupported ecosystem) gets a `skipped` row with the reason.
- Finds known vulnerabilities for that exact version in OSV.
- Merges duplicates. One issue often has several ids (for example GHSA, PYSEC and CVE). They become one row, and all ids are kept in `osvIds` and `aliases`.
- Picks the severity. The GitHub reviewed label comes first, then the highest CVSS score (v4, v3 or v2), then the ecosystem's own rating. With no score at all the row says `UNKNOWN`. When aliases are merged into one row, the highest level among them counts; on a tie the GitHub label wins.
- Finds the fix for your branch. `fixedIn` is the lowest version that fixes every merged advisory on the branch of your version. For `django 3.2.0` it is a 3.2.x version, not an older 2.2.x fix.

### Good for

- Check a project's `package-lock.json` or `requirements.txt` before a release.
- Get a list of packages to upgrade, with the target version for each.
- Add CVE, CVSS and CWE data to an SBOM or a dependency inventory.
- Run the same check on a schedule and export the rows to a spreadsheet or a ticket system.

### Not a good fit

- Proof that a package is safe. An empty result means OSV has no known advisory for that exact version. It does not prove the package is safe.
- Typos and unknown packages. OSV answers the same way for an unknown name and for a clean package, so both get a `no_known_vulnerabilities` row.
- Your code. The Actor checks package versions only. It does not scan source code, containers or OS packages (Debian, Alpine and similar are not supported).
- Version ranges. A range like `^4.17.15` is checked at its lowest version. For the versions you really install, paste the lockfile.

## Price

Prices will be shown after release.

## Questions

### Does an empty result mean I am safe?

No. It means OSV has no known issue for that version. It is not a proof of safety.

### Why do I see fewer rows than other scanners?

Duplicate ids for the same issue are merged into one row.

### Does it catch typos in package names?

No. OSV answers the same for an unknown name and a clean package.

### How many packages can I check?

Up to 2,000 unique packages per run.

### Why is the severity MEDIUM when the CVSS score is high?

GitHub has reviewed the advisory and set that label. The reviewed label comes first; `cvssScore` still shows the raw score.

### How fresh is the data?

Each run asks OSV live. Each row has `modified` (last change of the advisory) and `fetchedAt` (our read time).

## Data fields

- `resultType` (string): vulnerable = one known vulnerability of this dependency; below_severity_filter = OSV lists vulnerabilities for this version but all are below your minimum severity; no_known_vulnerabilities = OSV has no matching advisory (not a guarantee of safety); skipped = not checked (unsupported ecosystem, missing or unresolvable version); error = OSV could not be reached for this dependency.
- `ecosystem` (string): OSV ecosystem, e.g. npm, PyPI, Maven.
- `packageName` (string): Package name as sent to OSV, e.g. lodash, org.apache.logging.log4j:log4j-core.
- `version` (string): Version checked. Null when it could not be determined (skipped).
- `requestedVersionSpec` (string): Version text from your input, e.g. ^4.17.15 or >=2.19.1.
- `versionSource` (string): exact, range_minimum (lowest version of an npm range), lower_bound (requirements >= / ~=) or lockfile.
- `inputSource` (string): Where the dependency came from: dependencies, packageJson, packageLockJson or requirementsTxt.
- `dependencyType` (string): prod, dev, optional or peer (manifests only).
- `vulnerabilityId` (string): Main id of the vulnerability (GHSA preferred, then PYSEC/RUSTSEC/GO, then others, then CVE).
- `osvIds` (array): OSV records merged into this row because they describe the same issue.
- `aliases` (array): Other ids of the same issue (CVE, GHSA, PYSEC…), without duplicates.
- `cveIds` (array): CVE ids of the issue.
- `ghsaIds` (array): GitHub advisory ids of the issue.
- `summary` (string): One-line summary (max 500 characters).
- `details` (string): Advisory text (max 4000 characters).
- `severity` (string): CRITICAL, HIGH, MEDIUM, LOW or UNKNOWN. Null for non-vulnerable rows.
- `severitySource` (string): ghsa_database (GitHub reviewed label), cvss_v4, cvss_v3, cvss_v2 or ecosystem_specific.
- `cvssScore` (number): Highest CVSS base score in the group.
- `cvssVector` (string): CVSS vector for that score.
- `cvssVersion` (string): CVSS version, e.g. 3.1 or 4.0.
- `cweIds` (array): CWE weakness ids.
- `fixedIn` (string): Lowest version that fixes every merged advisory on the branch of your version. Null when no fix is published for that branch.
- `fixedVersions` (array): All fixed versions across branches.
- `affectedRanges` (array): Affected intervals for this package: {type, introduced, fixed, lastAffected}.
- `published` (string): Earliest publication time in the group (ISO 8601).
- `modified` (string): Latest modification time in the group (ISO 8601).
- `withdrawnAliases` (array): Aliases withdrawn by their database; they are listed for transparency and do not affect severity.
- `references` (array): Advisory, fix and report links: {type, url}, max 30.
- `advisoryUrl` (string): OSV.dev page of the vulnerability.
- `databaseSource` (string): Original advisory database link when OSV provides one.
- `errorCode` (string): For skipped/error rows: UNSUPPORTED_ECOSYSTEM, MISSING_VERSION, UNRESOLVABLE_VERSION, INVALID_DEPENDENCY, SOURCE_UNAVAILABLE, DEADLINE_REACHED…
- `message` (string): Human-readable explanation for below_severity_filter, clean, skipped and error rows.
- `provider` (string): Always OSV.dev.
- `fetchedAt` (string): When the row was produced (ISO 8601).

## Input settings

- `dependencies` (array): One per line: ecosystem:name@version, e.g. npm:lodash@4.17.15, PyPI:django==3.2.0, Maven:org.apache.logging.log4j:log4j-core@2.14.1, Go:github.com/gin-gonic/gin@v1.6.0. Package URLs (pkg:npm/lodash@4.17.15) work too. Without a prefix the default ecosystem is used. Via API you can also pass objects {"ecosystem": "npm", "name": "lodash", "version": "4.17.15"}. npm ranges like ^4.17.15 are checked at their lowest version.
- `packageJson` (string): Paste the whole package.json (max 1 MB). dependencies, devDependencies, optionalDependencies and peerDependencies are read; a range such as ^4.17.15 is checked at its lowest version (versionSource = range_minimum). For exact installed versions paste package-lock.json instead.
- `packageLockJson` (string): Paste package-lock.json (lockfile v1, v2 or v3, max 8 MB). Every installed package with its exact version is checked, transitive ones included. Linked and git/file dependencies are reported as skipped.
- `requirementsTxt` (string): Paste requirements.txt (max 1 MB). name==1.2.3 is checked exactly; >= and ~= are checked at the lower bound (versionSource = lower_bound); lines without a version, URLs and -r includes are reported as skipped.
- `defaultEcosystem` (string): Used for list lines without an ecosystem prefix, e.g. lodash@4.17.15.
- `minSeverity` (string): Hide vulnerabilities below this level (GHSA MODERATE counts as MEDIUM). Hidden vulnerabilities are not charged. A dependency whose vulnerabilities are all below the level gets one below_severity_filter row, so it never looks clean.
- `includeUnknownSeverity` (boolean): Some advisories (often PYSEC and Go) have no severity score. Keep them as severity UNKNOWN regardless of the minimum severity.
- `includeCleanDependencies` (boolean): Add one no_known_vulnerabilities row per dependency with no matching advisory, so you can see what was checked. Every checked dependency is charged either way.
- `includeDevDependencies` (boolean): Check devDependencies from package.json and dev packages from package-lock.json.
- `maxDependencies` (integer): Upper limit of unique dependencies checked in one run (after duplicates are merged). The rest are counted in RUN_SUMMARY as notCheckedOverLimit and not charged.

## Step by step on Apify

1. Open the Input tab. The form already has six packages: `npm:lodash@4.17.15`, `npm:minimist@1.2.0`, `npm:express@4.17.1`, `PyPI:requests@2.19.1`, `PyPI:pyyaml@5.3` and `npm:chalk@5.3.0`.
2. Click Start.
3. Open the Overview view in the Output tab. Check `severity`, `vulnerabilityId` and `fixedIn`.
4. Replace the list with your own packages, or paste a whole file into package.json, package-lock.json or requirements.txt.

## Use cases

| Task | Input | Key fields |
|---|---|---|
| Check a Node.js project | `packageLockJson` | `packageName`, `version`, `severity`, `fixedIn`, `dependencyType` |
| Check a Python project | `requirementsTxt` | `severity`, `cveIds`, `fixedIn`, `versionSource` |
| Only urgent issues | any input + `minSeverity: "HIGH"` | rows with `HIGH` or `CRITICAL` only |
| Enrich an SBOM or inventory | `dependencies` list | `cveIds`, `ghsaIds`, `cvssScore`, `cweIds`, `advisoryUrl` |

## Tips

- Use a lockfile, not only package.json. Exact versions give better results.
- Keep only HIGH and CRITICAL rows when you need a short urgent list.
- Check skipped rows. They show lines without a version or with an unknown ecosystem.

## Limits



- Up to 2,000 unique packages per run (`maxDependencies`, default 500). A lockfile can be up to 8 MB; `package.json` and `requirements.txt` up to 1 MB each.
- A full run of 2,000 vulnerable packages took about 5.5 minutes in our test. The internal time budget is 10 minutes. Packages not reached in time get `error` rows and the run is `CAPPED`. Keep the run timeout at 900 seconds or more for large inputs.
- Only exact versions are checked. Ranges are checked at their lowest version, and lines without a version are skipped.
- The data is only as complete as OSV. A new advisory can take time to appear, and some advisories have no score or no fix yet.

## Sample result

```json
{
  "resultType": "vulnerable",
  "ecosystem": "npm",
  "packageName": "minimist",
  "version": "1.2.0",
  "requestedVersionSpec": "1.2.0",
  "versionSource": "exact",
  "inputSource": "dependencies",
  "vulnerabilityId": "GHSA-xvch-5gv4-984h",
  "osvIds": ["GHSA-xvch-5gv4-984h"],
  "aliases": ["CVE-2021-44906"],
  "cveIds": ["CVE-2021-44906"],
  "ghsaIds": ["GHSA-xvch-5gv4-984h"],
  "summary": "Prototype Pollution in minimist",
  "severity": "CRITICAL",
  "severitySource": "ghsa_database",
  "cvssScore": 9.8,
  "cweIds": ["CWE-1321"],
  "fixedIn": "1.2.6",
  "advisoryUrl": "https://osv.dev/vulnerability/GHSA-xvch-5gv4-984h",
  "provider": "OSV.dev"
}
```

## Similar tools

- [Link Route Audit — Bulk HTTP Status & Redirects](https://cliqtomedia.com/actors/bulk-url-status-redirect-checker/)
- [GitHub Releases Monitor & Scraper](https://cliqtomedia.com/actors/github-releases-monitor-scraper/)
- [Software End-of-Life Checker](https://cliqtomedia.com/actors/software-end-of-life-checker/)
- [GitHub Repositories & Users Search (No Login)](https://cliqtomedia.com/actors/github-search/)
- [OpenAPI Catalog & Breaking Change Detector](https://cliqtomedia.com/actors/openapi-spec-catalog-diff/)
- [SSL Certificate Checker: Expiry, Chain & CT, No Login](https://cliqtomedia.com/actors/ssl-certificate-inspector/)
