Dependency Vulnerability Scanner (OSV) avatar

Dependency Vulnerability Scanner (OSV)

Pricing

from $2.52 / 1,000 vulnerability founds

Go to Apify Store
Dependency Vulnerability Scanner (OSV)

Dependency Vulnerability Scanner (OSV)

Check npm, PyPI, Maven, Go, Cargo and 9 more ecosystems for known vulnerabilities via OSV.dev. Paste a list, package.json, package-lock.json or requirements.txt; get one deduplicated row per CVE/GHSA with severity, CVSS and the fix for your version.

Pricing

from $2.52 / 1,000 vulnerability founds

Rating

0.0

(0)

Developer

Cliqto Media

Cliqto Media

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Security

Limited permissions

Share

Dependency Vulnerability Scanner checks your npm, PyPI, Maven, Go, Cargo and other packages for known vulnerabilities in the free 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.

It is made for developers, security reviews and CI checks. No login and no API key are needed. The form example (6 packages) finishes in a few seconds and costs $0.0572.

Dependency Vulnerability Scanner: a manifest goes in, one row per known vulnerability comes out with severity and the fix version

Contents

What it does

The Actor asks the public OSV API live at run time. OSV collects advisories from the GitHub Advisory Database, PyPA, RustSec, the Go vulnerability database and other sources.

For each package version the Actor:

  1. 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.
  2. Finds known vulnerabilities for that exact version in OSV.
  3. 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.
  4. 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.
  5. 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.

Supported ecosystems: npm, PyPI, Maven, Go, crates.io, RubyGems, NuGet, Packagist, Pub, Hex, Hackage, CRAN, SwiftURL and GitHub Actions.

Good fit

  • 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 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.

Quick start

  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.

Expected result: 16 rows in a few seconds. On 2026-10-13 they were 15 vulnerabilities (3 critical, 3 high, 8 medium, 1 low) in 5 packages and one no_known_vulnerabilities row for chalk 5.3.0.

Use cases

Buyer jobInputKey fields
Check a Node.js projectpackageLockJsonpackageName, version, severity, fixedIn, dependencyType
Check a Python projectrequirementsTxtseverity, cveIds, fixedIn, versionSource
Only urgent issuesany input + minSeverity: "HIGH"rows with HIGH or CRITICAL only
Enrich an SBOM or inventorydependencies listcveIds, ghsaIds, cvssScore, cweIds, advisoryUrl

Input

You can combine the list and the files in one run. At least one of dependencies, packageJson, packageLockJson or requirementsTxt is needed.

FieldTypeDefaultWhat it does
dependencieslist of stringsform example: 6 packagesOne package 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. Through the API you can also pass objects {"ecosystem": "npm", "name": "lodash", "version": "4.17.15"}. Max 5,000 lines.
packageJsontextemptyThe whole package.json (max 1 MB). dependencies, devDependencies, optionalDependencies and peerDependencies are read. A range is checked at its lowest version.
packageLockJsontextemptyThe whole package-lock.json, lockfile v1, v2 or v3 (max 8 MB). Every installed package with its exact version is checked, transitive ones too.
requirementsTxttextemptyThe whole requirements.txt (max 1 MB). name==1.2.3 is checked exactly. >= and ~= are checked at the lower bound.
defaultEcosystemone of 14 ecosystemsnpmUsed for list lines without a prefix, e.g. lodash@4.17.15.
minSeverityLOW, MEDIUM, HIGH, CRITICALLOWHide vulnerabilities below this level. GitHub's MODERATE counts as MEDIUM.
includeUnknownSeveritybooleantrueKeep vulnerabilities without any score (often PYSEC and Go) as UNKNOWN, whatever minSeverity is.
includeCleanDependenciesbooleantrueAdd one no_known_vulnerabilities row for each package with no advisory, so you can see what was checked.
includeDevDependenciesbooleantrueCheck dev dependencies from package.json and package-lock.json.
maxDependenciesinteger 1–2000500The most unique packages checked in one run. The rest are counted in RUN_SUMMARY as notCheckedOverLimit, not checked and not charged.

The same package and version from several sources is checked once and counted in duplicatesMerged. If nothing in the input can be read, the run fails with INVALID_INPUT and the status message says why.

Interacting settings

  • minSeverity + includeUnknownSeverity: with minSeverity: "HIGH" and the default includeUnknownSeverity: true, you get HIGH, CRITICAL and UNKNOWN rows. Set it to false to drop UNKNOWN.
  • minSeverity never makes a package look clean. If all its vulnerabilities are below the level, it gets one below_severity_filter row with the highest hidden severity.
  • includeCleanDependencies: false removes clean rows only. skipped, error and below_severity_filter rows are always written.

Input examples

Check a Python project and keep only urgent issues:

{
"requirementsTxt": "Django==3.2.0\nrequests>=2.19.1\npyyaml==5.3\nnumpy\n",
"minSeverity": "HIGH",
"includeUnknownSeverity": false
}

Expected result: HIGH and CRITICAL rows for Django, requests and PyYAML (requests is checked at 2.19.1, versionSource: "lower_bound"). numpy has no version, so it gets a skipped row with MISSING_VERSION.

Check a lockfile without dev packages:

{
"packageLockJson": "{\"lockfileVersion\": 3, \"packages\": {\"\": {}, \"node_modules/minimist\": {\"version\": \"1.2.0\"}}}",
"includeDevDependencies": false,
"maxDependencies": 2000
}

Output

One Dataset row per vulnerability, plus one row per clean, filtered, skipped or failed package. The Overview view shows the main fields, Details shows the advisory text and links, Inputs shows where each package came from.

Row types

resultTypeMeaning
vulnerableOne known vulnerability of this package version.
below_severity_filterOSV lists vulnerabilities for this version, but all are below minSeverity. message names the highest one.
no_known_vulnerabilitiesOSV has no advisory for this exact version. Not a guarantee of safety.
skippedNot checked: no version, a range or URL that cannot be resolved, an unsupported ecosystem or an include line. See errorCode and message.
errorOSV did not answer for this package (outage or the run's time limit). Run it again later.

Main fields

FieldMeaning
ecosystem, packageName, versionThe package version that was checked.
requestedVersionSpec, versionSourceYour original version text and how the version was chosen: exact, range_minimum, lower_bound or lockfile.
inputSource, dependencyTypeWhere the package came from (dependencies, packageJson, packageLockJson, requirementsTxt) and prod, dev, optional or peer.
vulnerabilityIdThe main id: GHSA first, then PYSEC, RUSTSEC, GO and others, then CVE.
osvIds, aliases, cveIds, ghsaIdsAll ids of the same issue. Use them to match rows with other tools.
severity, severitySourceCRITICAL, HIGH, MEDIUM, LOW or UNKNOWN, and where it came from: ghsa_database, cvss_v4, cvss_v3, cvss_v2 or ecosystem_specific.
cvssScore, cvssVector, cvssVersionThe highest CVSS base score in the group and its vector.
cweIdsWeakness types, e.g. CWE-1321.
fixedInThe lowest version that fixes every merged advisory on your version's branch. null when no fix is published for that branch.
fixedVersions, affectedRangesAll fixed versions across branches and the affected intervals.
summary, details, references, advisoryUrlAdvisory text (up to 4,000 characters) and links.
published, modifiedEarliest publication and latest change in the group.
withdrawnAliasesAliases withdrawn by their database. They are listed but do not change the severity.
errorCode, messageReason for skipped and error rows, explanation for clean and filtered rows.

How severity and fixedIn are read

  • The severity follows GitHub when GitHub has reviewed the advisory. So a row can say MEDIUM while cvssScore is 7.9: GitHub rated it lower than the raw CVSS score. This is the same label you see on GitHub.
  • fixedIn stays on your branch. For minimist 1.2.0 the fix is 1.2.6, not 0.2.4 from the old 0.x branch. When merged advisories need different fixes, the highest one is used, so upgrading to fixedIn closes them all.
  • An advisory can have no fix yet. Then fixedIn is null.

Output example

{
"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"
}

This example is trimmed. It comes from the form example run on 2026-10-13.

Run summary

The RUN_SUMMARY record in the Key-value store has status, a plain message, counts (checked, vulnerable, clean, skipped, failed, by severity), charged events and the data licence. status is one of:

  • SUCCEEDED: every package was checked;
  • PARTIAL: OSV failed during the run; packages not checked have error rows;
  • CAPPED: the run stopped at your maximum cost or at the internal time limit, or more unique packages than maxDependencies were found;
  • ERROR: OSV could not be reached, no package was checked;
  • INVALID_INPUT: the input is wrong or nothing in it can be checked (the run fails and the message says why);
  • CANCELLED: you stopped the run; rows written before that are kept.

Coming from another OSV scanner

Many scanners write one row per OSV record. This Actor merges records of the same issue, so you get fewer rows with the same set of ids (osvIds + aliases). Field names differ too: look for packageName, vulnerabilityId, cveIds, fixedIn and resultType.

Pricing

Pay per event. Platform usage is included.

EventPriceWhen
Actor start$0.002Once per run (per GB of memory; the default 256 MB counts once)
Vulnerability found$0.0036 (Free plan), $0.0034 (Bronze), $0.0032 (Silver), $0.0030 (Gold and higher)Each vulnerable row saved to the Dataset
Dependency checked$0.0002Each unique package version that OSV answered for, clean or not

skipped and error rows are free. Vulnerabilities hidden by minSeverity are free, but the package still counts as checked.

Run (Free plan prices)Example cost
Form example: 6 packages, 15 vulnerabilities$0.0572
100 packages, none vulnerable$0.022
100 packages, 20 vulnerabilities$0.094
500 packages, 50 vulnerabilities$0.282
Nothing can be checked (only skipped rows, run fails with INVALID_INPUT)$0.002

Set a maximum cost per run in the run options to cap your spend. The Actor stops before a package whose rows do not fit and reports CAPPED.

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.

API and integrations

Start a run with the same JSON input through the Apify API (POST /v2/acts/cliqtomedia~osv-dependency-vulnerability-scanner/runs), then read the Dataset. Export to CSV, Excel or JSON from the Dataset, or connect the run to other tools with the usual Apify integrations.

To check a project regularly, save the input as a task and add an Apify schedule. The Actor keeps no state between runs, so each run reports all known vulnerabilities again.

Use with AI agents (MCP)

AI agents can call this Actor through the Apify MCP server: add https://mcp.apify.com?tools=cliqtomedia/osv-dependency-vulnerability-scanner to your MCP client (Claude, Cursor, VS Code and others). The MCP server needs your Apify account (OAuth sign-in or an Apify API token); OSV itself needs no key. The smallest useful input:

{ "dependencies": ["npm:lodash@4.17.15", "npm:minimist@1.2.0", "npm:express@4.17.1", "PyPI:requests@2.19.1", "PyPI:pyyaml@5.3", "npm:chalk@5.3.0"] }

Key output fields for an agent: resultType, packageName, version, severity, vulnerabilityId, cveIds and fixedIn. A call with up to about 100 packages usually finishes in under 30 seconds. skipped rows carry an errorCode and a message that the agent can use to fix the input.

Troubleshooting

SymptomCheckAction
A package you know is vulnerable shows no_known_vulnerabilitiespackageName, ecosystem, versionCheck the spelling and the ecosystem. OSV treats an unknown name like a clean one. Some advisories are filed under another package name (for example Rails issues under actionpack).
skipped with MISSING_VERSION or UNRESOLVABLE_VERSIONrequestedVersionSpecGive an exact version, or paste the lockfile instead of package.json.
skipped with UNSUPPORTED_ECOSYSTEMecosystemUse one of the 14 supported ecosystems. OS packages are not supported.
error rows or PARTIALRUN_SUMMARY.messageOSV did not answer. Run again later.
CAPPEDRUN_SUMMARY.message, counts.notCheckedOverLimitRaise maxDependencies (up to 2,000) or your maximum cost per run, or split a very large input into two runs.
Run failed with INVALID_INPUTthe run status messageTypical causes: empty input, a file that is not valid JSON, a file over the size limit.

FAQ

Does an empty result mean my project is safe?

No. It means OSV has no known advisory for those exact versions today. New advisories appear every day, and an unknown package name is reported the same way as a clean one.

Why do I get fewer rows than other scanners?

Records of the same issue (for example a GHSA and a PYSEC record of one Django bug) are merged into one row. All their ids are in osvIds and aliases.

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 source and licence

Data: OSV.dev, which aggregates the GitHub Advisory Database, PyPA, RustSec, Go and other databases under their own licences (mostly CC-BY 4.0). Each row links to its source in databaseSource and advisoryUrl. This Actor is independent and not affiliated with or endorsed by OSV.dev, Google or GitHub.

Support

Use the Issues tab of this Actor. Add the run ID, the input mode and the row you did not expect. Do not send API tokens or private code.