Skip to content

Dependency vulnerabilities

Shield360 finds vulnerable open-source packages in three ways. All three land in Protect → Application security → Code security, each as its own target:

Target typeWhere the package list comes fromWhat you install
filesystem, imageshield360 scan in CI or on a laptopThe Shield360 CLI
runtimeThe packages each app’s Shield360 SDK reports from its running processNothing more than the SDK
repositoryThe lock files of a connected GitHub repository, once you turn it on for that repositoryNothing

This page covers the two server-side paths, runtime and repository, and the matching they share. Each target keeps the findings of its latest match only, plus a history of its counts.

Every Shield360 SDK that is given a Shield360 URL and API key reports the packages its process runs: the language runtime and each package’s name and version. The report goes to /api/guard/events with the app’s API key, shortly after the app starts and then once a day.

SDKWhat it reports
TypeScriptnpm packages loaded through require, plus the app’s direct dependencies as installed
PythonThe distributions of every module imported so far, then the other installed distributions (importlib.metadata)
GoThe modules the binary was built with (runtime/debug.ReadBuildInfo) and the Go version
.NETThe NuGet packages of the assemblies loaded, from the app’s .deps.json
Java, PHP, RustThe same report, when runtime protection is on

Because the list comes from the running process, a finding on a runtime target means the vulnerable package is loaded in that app, not only declared somewhere in a repository.

Turn the report off per app with the SDK option (runtimePackages: false in TypeScript, runtime_packages=False in Python, DisableRuntimePackages in Go, RuntimePackages = false in .NET) or the environment variable SHIELD360_RUNTIME_PACKAGES=off.

Only package names and versions, the app’s service name, its environment, the host name and the SDK version. No file path, source code, environment variable or configuration value is sent. At most 500 packages are reported per process.

Repositories you connected for AI code tracking (a GitHub scanner connector with a read-only token) can also have their dependencies scanned. Nothing needs installing in the repository or in CI. The scan is off for every repository until someone with Manage AI app security turns it on for that repository: open Protect → Application security → Code security → Repositories and switch it on for the repository. The same setting is available through the API with PATCH /api/code-security/repositories and a body that names the connector:

{ "connectorId": "<connector id>", "dependencyScan": true }

GET /api/code-security/repositories lists the current project’s repositories with their setting and last scan. Every change is recorded in the audit log with the setting before and after. Turning the scan off also deletes what it stored for that repository.

When it is on, Shield360 runs a first scan straight away, then one every day:

  1. It reads the branch’s head commit (the connector’s branch, or the repository’s default branch) and the list of file names in its tree.
  2. It fetches only the lock and manifest files below, by blob, through the GitHub API. Nothing is cloned and no other file is read. Files under node_modules, vendor, dist, build, target, .venv and similar directories are skipped, and the scan reads at most 40 files, each up to 5 MB, 20 MB in total.
  3. It parses them inside Shield360, keeps each package’s name, exact version and the file it came from, and discards the file contents.
  4. It matches the packages against OSV and stores the result as the repository’s repository target, named owner/repo@branch, with the commit.

When the head commit has not moved since the last scan, the stored package list is matched again without reading GitHub, so new advisories still appear.

EcosystemFiles read
npmpackage-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock (classic and Berry)
PyPIrequirements*.txt (pinned == lines only), poetry.lock, Pipfile.lock
Gogo.mod (require lines; // indirect marks transitive modules)
crates.ioCargo.lock (registry and git crates; the workspace’s own crates are left out)
RubyGemsGemfile.lock
NuGetpackages.lock.json
Mavenpom.xml (dependencies with a literal version; ${property} versions are skipped), gradle.lockfile

Version ranges (such as ^1.2 in a package.json) cannot be matched, so only lock files and pinned versions count. Secret scanning and reading source code are not part of this; use shield360 scan in CI for those.

The repository’s file list for one commit, and the contents of the lock and manifest files above. Shield360 keeps only package names, versions, file paths of those lock files, the branch and the commit. The token stays on the connector and is never shown or logged.

Once a day Shield360 reads the packages each app reported in the last two days and looks them up in OSV.dev, the open-source vulnerability database run by Google. The result is stored as that app’s runtime target, so an advisory published since yesterday appears without anyone scanning again.

  • What Shield360 sends to OSV: package ecosystem, name and version. Never your app, organization, host or file names.
  • Caching: OSV’s answers are cached for every organization alike, since they are public data: which advisories affect a package version for 20 hours, and each advisory until OSV reports it changed.
  • Severity: computed from the advisory’s CVSS v3 vector (or v2), and otherwise taken from the source database’s own label (for example GitHub’s MODERATE is shown as MEDIUM). An advisory with neither is UNKNOWN. CVSS v4 vectors are not scored; their database label is used.
  • Fixed version: the versions the advisory says fix the package, joined when there are several.
  • Withdrawn advisories are left out.
  • When OSV cannot be reached, nothing is stored for that app, so its previous result stands until the next run.

Supported ecosystems: npm, PyPI, Go (modules and the standard library), Maven, NuGet, crates.io, RubyGems and Packagist.

The daily match needs outbound HTTPS to api.osv.dev. Two environment variables on the Shield360 server change that:

VariableEffect
SHIELD360_OSV=offNo lookups leave the deployment; runtime and repository targets are not matched.
SHIELD360_OSV_URLAn HTTPS mirror that serves OSV’s /v1/querybatch and /v1/vulns/{id} API.
CODE_SECURITY_MATCH_SCHEDULEThe cron schedule of the daily match (default 41 3 * * *).

OSV.dev aggregates advisories from other databases, each under its own license. Each stored advisory keeps the database it came from, which you can tell from its id:

Id prefixDatabaseLicense
GHSA-GitHub Advisory DatabaseCC-BY-4.0
PYSEC-PyPI Advisory DatabaseCC-BY-4.0
GO-Go Vulnerability DatabaseCC-BY-4.0
RUSTSEC-RustSec Advisory DatabaseCC0-1.0
MAL-OpenSSF Malicious PackagesApache-2.0

Shield360 does not redistribute this data; it fetches it at run time and caches it.