AI Agent Stack Dependency Vulnerability Scanner
Pricing
from $50.00 / 1,000 manifest scanneds
AI Agent Stack Dependency Vulnerability Scanner
Resolve packages from a supplied dependency manifest, query the public OSV.dev advisory database, and return a ranked, import-checked fix list plus one pass/fail gate.
Pricing
from $50.00 / 1,000 manifest scanneds
Rating
0.0
(0)
Developer
kingii98
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Give this Actor one or more dependency manifests as plain text. The Actor reads the packages named in each manifest, queries the public OSV.dev advisory database, and reports each vulnerable package with a CVSS score, a fix version, and an import-presence flag. It also writes one run-level pass/fail gate. The Actor answers one question: does this manifest pull in a known vulnerable package, and does the supplied source code import it?
The Actor does not clone a repository, install a package, or run any code from a manifest. It reads the text you supply and calls the public OSV.dev API only.
Supported ecosystems
| Ecosystem | Manifest text read | Heuristic notes |
|---|---|---|
PyPI | requirements.txt-style lines (name==version) | Only exact == pins resolve; ranges and unpinned lines are skipped. |
npm | package.json, or an npm package-lock.json (v1 or v2/v3) | A lock file's node_modules/ nesting marks transitive packages. A plain package.json strips a ^/~/range prefix to get a best-effort version and marks every entry DIRECT. |
Go | go.mod | A // indirect comment marks a requirement TRANSITIVE. |
Maven | pom.xml <dependency> blocks | Read with a bounded regex extraction, not an XML parser, so a manifest cannot trigger XML entity expansion. A version that is still a ${property} placeholder cannot be resolved and is skipped. Every entry is marked DIRECT: a plain pom.xml does not show the resolved dependency tree. |
crates.io | Cargo.toml [dependencies] tables, or a Cargo.lock | Every entry is marked DIRECT: a version 1 scanner does not walk Cargo.lock's own dependency graph. |
This is a heuristic manifest reader, not a package manager's dependency solver. It does not compute a lock file from a bare manifest, and it does not run call-graph analysis. The importPresence field is a plain text search for the package name in the source files you supply — a name match, not proof that the vulnerable code path is reachable.
Input
{"manifests": [{"name": "requirements.txt", "ecosystem": "PyPI", "content": "django==1.11.1\nsix==1.16.0\n"}],"sourceFiles": [{"path": "app/settings.py", "content": "import django\n"}],"minCvss": 0.0,"includeTransitive": true,"failOnCvssAtOrAbove": 9.0}
| Field | Description |
|---|---|
manifests | 1-20 manifests. Each has name, ecosystem (PyPI, npm, Go, Maven, or crates.io), and content (the manifest text). Required. |
sourceFiles | Optional, up to 2000 files. Each has path and content. Used only for the importPresence text search. |
minCvss | Drop advisories below this CVSS score from the report and the gate. Default 0.0. |
includeTransitive | Resolve transitive packages when the manifest text carries that information. Default true. |
failOnCvssAtOrAbove | The gate fails when any reported advisory's CVSS score is at or above this value. Default 9.0. |
A run resolving more than 5000 packages across all manifests fails before any OSV.dev call is made.
Output
Every run writes one package-result record for each resolved package that has at least one advisory at or above minCvss, plus one gate-result record, to the default dataset.
Package result:
{"recordType": "package-result","manifestName": "requirements.txt","ecosystem": "PyPI","packageName": "django","resolvedVersion": "1.11.1","dependencyKind": "DIRECT","vulnerabilities": [{"osvId": "GHSA-xxxx","aliases": ["CVE-2021-1234"],"summary": "SQL injection in QuerySet","cvssScore": 9.8,"cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","severityBand": "CRITICAL","introducedVersion": "0","fixedVersion": "1.11.5","publishedAt": "2021-01-01T00:00:00Z"}],"importPresence": {"searched": true, "matchedFiles": ["app/settings.py"], "verdict": "IMPORTED"},"upgradePath": {"currentVersion": "1.11.1", "lowestSafeVersion": "1.11.5", "isMajorBump": false}}
importPresence.verdict is IMPORTED, NOT_IMPORTED, or UNKNOWN (no sourceFiles were supplied, so nothing was searched).
Gate result:
{"recordType": "gate-result","gate": {"verdict": "FAIL", "highestCvss": 9.8, "failingPackageCount": 1, "threshold": 9.0},"summary": {"severityCounts": {"CRITICAL": 1, "HIGH": 0, "MEDIUM": 0, "LOW": 0, "NONE": 0, "UNKNOWN": 0},"rankedFixList": [{"manifestName": "requirements.txt","packageName": "django","resolvedVersion": "1.11.1","highestCvss": 9.8,"imported": "IMPORTED","lowestSafeVersion": "1.11.5"}]}}
rankedFixList is ordered by highestCvss descending, then by IMPORTED packages first. When gate.verdict is FAIL, the Actor run itself finishes with a non-zero exit code and a failed status message, so a CI job can gate a merge on the run outcome alone.
CVSS scoring
OSV.dev advisory records carry a CVSS v3 vector string, not a precomputed score. The Actor computes the CVSS v3.1 base score from that vector using the published formula. When an advisory has no CVSS v3 vector, cvssScore is null and severityBand falls back to the advisory's own qualitative severity label (or UNKNOWN when neither is present). A minCvss above 0.0 drops an unscored advisory rather than guessing whether it clears the floor.
Pricing
The Actor uses Apify pay-per-event pricing with three charge events:
| Event | Charged | Price |
|---|---|---|
manifest-scanned | Once for each manifest in the input, parsed, resolved, and queried, whether or not it resolves to any package. | $0.05 |
package-resolved | Once for each package resolution. The same package repeated across manifests is charged once per manifest it appears in, because parsing it cost CPU again each time. | $0.0006 |
vulnerability-detailed | Once for each distinct OSV.dev advisory actually retrieved and enriched. A package/version pair repeated across manifests reuses the same OSV.dev query and detail fetch, so the advisory is charged once, not once per manifest. | $0.004 |
Apify platform usage (compute units and other resources consumed by the run) may still be shown to users according to their plan and Apify's pricing rules, as described in the Actor's listing.
Final pricing is configured in the Apify Store listing and may change subject to Apify's pricing-change notice rules.
Security and privacy
- The Actor never fetches a URL you supply. It reads the manifest and source file text you pass in input, and it calls only the fixed, public OSV.dev API.
- The Actor does not use a browser, proxy, LLM, external database, or paid API.
- The Maven manifest reader is a bounded regex extraction, not an XML parser, so a
pom.xmlcannot trigger XML entity expansion. - Manifest count, resolved package count, source file count, and per-field text length are all bounded before parsing begins.
Do not place secrets, private tokens, or personal data in any input field.
Limitations
- Version resolution is heuristic: only exact pins resolve for
PyPI;npm,Maven, andcrates.iomanifests without a lock file report the versions stated in the manifest text, not a real dependency solver's result. dependencyKind(DIRECT/TRANSITIVE) is only inferred where the manifest text itself carries that structure (an npm lock file's nesting, or ago.mod// indirectmarker). Every other ecosystem reportsDIRECTfor every entry.importPresenceis a plain-text name search across the supplied source files. It is a signal, not proof of reachability: it can both miss a dynamic import and match an unrelated identifier that happens to share the package's name.- Version comparison for
upgradePathandminCvssfiltering uses a generic leading-numeric comparator, not each ecosystem's own version scheme (PEP 440, semver, Maven versioning, ...). Pre-release suffixes and epoch markers are ignored. - The OSV.dev API is queried live; the Actor stores no advisory data between runs.
Support
For reproducible issues, open an issue from the Actor page and include the Apify run ID, sanitized input, and expected result. Do not include API tokens or private data.