# SecurityContext API

> Look up the security context of any open-source repository, organization, package, native library, NVD product or CVE: what it depends on, which vulnerabilities and malicious packages reach it, what leaked, how it was fixed before and what its code can do.
> Listed means exposed, not breached.

Base URL: https://api.securitycontext.com. Every route is a GET that returns JSON, except POST /v1/scans.

## Start here

- /v1/index: dataset date, scope and counts
- /v1/tools: every endpoint as a JSON-schema function definition, ready to use as a model's tool list
- /v1/openapi.json and /v1/docs: the full contract

## Rate limit

- 10 requests per 60 s per client address. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
- Over the limit: 429 with Retry-After and a JSON body (code rate_limited, retry_after_seconds, higher_limits).
- Higher limits: https://neo.projectdiscovery.io
- /, /healthz, /v1/docs and /v1/openapi.json are not counted.

## Nouns (everything is one of these)

### repositories: a public GitHub repository in the index and everything it is exposed to
- lookup: /v1/repositories/{owner}/{name}
- list: /v1/repositories
  - filters: in_scope, capability, organization, company, contributor, finding, exploit, severity, min_stars, pushed_since, cve, advisory, package, library, bundled_in, upstream, runtime, context, signal
  - sort: risk_score, stars, last_pushed_at, severity; facets: severity, organization, finding
  - include= on the lookup: dependencies, libraries, published_packages, contributors, secret_leaks, security_fixes
- /v1/repositories/{owner}/{name}/risk: score breakdown and the cheapest path an attacker has
- /v1/repositories/{owner}/{name}/contributors: write access and credential-leak flags per person
- /v1/repositories/{owner}/{name}/secret-leaks: leaked secrets by provider, category and status (no locations)
- /v1/repositories/{owner}/{name}/security-fixes: confirmed historical security fixes in the repository's own code, newest first; severity= narrows
- /v1/repositories/{owner}/{name}/project-cves: CVEs filed against the repository's own code (not its dependencies), newest first; severity=, exploit=, sort=published_date|cvss_score|epss_score, facets=severity,exploit,year
- example: /v1/repositories/facebook/react?include=dependencies,libraries

### organizations: a GitHub owner with at least one indexed repository
- lookup: /v1/organizations/{org}
- list: /v1/organizations
  - filters: company, finding, exploit, min_stars, tier, cve, advisory, package, library, contributor, signal
  - sort: max_risk_score, stars, repositories; facets: company, tier
  - include= on the lookup: dependencies, libraries, contributors, secret_leaks
- /v1/organizations/{org}/risk: risk summary, entry points and a fix plan
- /v1/organizations/{org}/contributors: staff, pushers and committers with a credential leak
- /v1/organizations/{org}/secret-leaks: secret-leak counts by status and severity
- example: /v1/organizations/vercel/risk

### packages: a published package (ecosystem + name), its versions, advisories and maintainers
- lookup: /v1/packages/{ecosystem}/{name}  and  /v1/packages/{ecosystem}/{name}/versions/{version}
- list: /v1/packages
  - filters: ecosystem, used_by, repository, library, cve, advisory, severity, exploit, malicious, runtime, context, signal
  - sort: dependents, worst_severity; facets: ecosystem, severity
- /v1/packages/{ecosystem}/{name}/advisories: every advisory with affected and fixed versions
- /v1/packages/{ecosystem}/{name}/maintainers: maintainers with credential-leak flags
- example: /v1/packages/npm/sharp

### libraries: a native (C/C++) library bundled inside packages, e.g. libheif inside sharp
- lookup: /v1/libraries/{name}  and  /v1/libraries/{name}/versions/{version}
- list: /v1/libraries
  - filters: package, repository, cve, advisory, category, format, input_facing, advisory_feed, unmined, company, signal
  - sort: score, reach, advisories, memory_safety_share; facets: category, format, company, advisory_feed
- /v1/libraries/{name}/advisories: bug history from the per-repo and distro feeds
- /v1/libraries/{name}/timeline: advisories per year and memory-safety share
- /v1/libraries/{name}/security-fixes: the upstream's confirmed historical security fixes in its own code, newest first; severity= narrows
- example: /v1/libraries/libheif

### products: a product NVD names (vendor:product, e.g. f5:nginx, apache:log4j), its CVEs and which affect one version
- lookup: /v1/products/{vendor}/{product}  and  /v1/products/{vendor}/{product}/versions/{version}
- list: /v1/products
  - filters: vendor, part, exploit, cve, signal
  - sort: score, cves, known_exploited_cves, last_cve_date; facets: part, vendor
- /v1/products/{vendor}/{product}/advisories: every CVE naming the product, with NVD's affected ranges, newest first
- /v1/products/{vendor}/{product}/versions/{version}: the CVEs affecting that version, each with the basis of the verdict; undecidable ones listed apart
- example: /v1/products/apache/log4j/versions/2.14.1

### cves: every CVE with a record: search by keyword, severity, exploit type, vendor or product, CWE, CVSS / EPSS floors and dates; one CVE's full record: description, CVSS, CWE, KEV entries, references, public exploit links, nuclei templates, HackerOne, the NVD products it affects and how far it reaches into the index
- lookup: /v1/cves/{cve}
- list: /v1/cves
  - filters: severity, exploit, vendor, product, cwe, min_cvss, min_epss, published_since, published_before, rejected, indexed, oss, changed, changed_since, ecosystem, signal
  - sort: published_date, epss_score, cvss_score, repositories, modified_date; facets: severity, exploit, cwe, vendor, year
  - include= on the lookup: history, references, public_exploits, products
- example: /v1/cves/CVE-2021-44228

### scans: a scan job: a request to scan one public GitHub repository that is not in the index yet (or to refresh it), and its progress and result
- lookup: /v1/scans/{id}
- list: /v1/scans
  - filters: repository
- create: POST /v1/scans with {"repository": "owner/name"} (or a https://github.com/owner/name URL) queues a scan; add "security_fixes": false to skip the security-fix history (default true). Answers 202 with the job and a Location header. An address may start 3 new scans per hour (joining a queued scan is free), then gets 429 (code scan_limit, Retry-After). A repository already queued or running answers 200 with the same job and deduplicated:true; a full queue answers 429 (code queue_full) with Retry-After
- example: /v1/scans?repository=facebook/react

## Examples (complete GET URLs)

### lookups

- GET https://api.securitycontext.com/v1/repositories/facebook/react
  returns: one repository: stars, severity, findings, risk score, totals for dependencies, libraries, contributors, secret leaks
- GET https://api.securitycontext.com/v1/repositories/facebook/react?include=dependencies,libraries
  returns: the same plus the first 50 dependencies and bundled native libraries, each section with a total and a link to the full list
- GET https://api.securitycontext.com/v1/repositories/facebook/react?fields=repository,stars,severity,findings
  returns: the same repository trimmed to just those fields
- GET https://api.securitycontext.com/v1/organizations/vercel
  returns: one organization: company, tier, repositories, worst repository, findings
- GET https://api.securitycontext.com/v1/packages/npm/sharp
  returns: one package: dependents, versions indexed, worst severity, malicious and known-exploited flags, upstream repository, bundled libraries
- GET https://api.securitycontext.com/v1/packages/pypi/httpxv3
  returns: any package the malicious-package catalog lists, even one no indexed repository uses: indexed:false, malicious, and its advisories with the versions they cover
- GET https://api.securitycontext.com/v1/packages/npm/lodash/versions/4.17.20
  returns: one package version: advisories affecting it and dependents pinned to it
- GET https://api.securitycontext.com/v1/libraries/libheif
  returns: one native library: category, formats decoded, carriers, reach across the index, advisory feed, research score
- GET https://api.securitycontext.com/v1/libraries/libheif/versions/1.20.2
  returns: one library build: which carrier packages ship it and the advisories matched to that build
- GET https://api.securitycontext.com/v1/products/f5/nginx
  returns: one NVD product: CVE counts by severity, known exploited, public exploits, nuclei templates, max CVSS and EPSS, exposed hosts, versions NVD knows, its GitHub repository and the native library it is
- GET https://api.securitycontext.com/v1/cves/CVE-2021-44228
  returns: one CVE's full record: description, severity, CVSS score and vector, EPSS, CWE, KEV entries (list, added, due, ransomware use), references, public exploit links, nuclei templates, HackerOne, the NVD products it affects with their ranges, and the repositories and packages in the index exposed to it
- GET https://api.securitycontext.com/v1/products/apache/log4j/versions/2.14.1
  returns: the CVEs affecting that exact version, each with match.basis (version_list: NVD lists the version; exact_version, range: our comparison of NVD's rule; all_versions) and NVD's affected ranges; undetermined ones apart

### sub resources

- GET https://api.securitycontext.com/v1/repositories/facebook/react/risk
  returns: risk breakdown and the cheapest path an attacker has into this repository
- GET https://api.securitycontext.com/v1/repositories/facebook/react/contributors
  returns: contributors with write access and credential-leak flags (username plus masked e-mail)
- GET https://api.securitycontext.com/v1/repositories/facebook/react/secret-leaks
  returns: leaked secrets by provider, category and status; no file locations
- GET https://api.securitycontext.com/v1/repositories/0xJacky/nginx-ui/security-fixes
  returns: confirmed historical security fixes in the repository's own code: commit, date, class, CWE, severity, files
- GET https://api.securitycontext.com/v1/repositories/0xJacky/nginx-ui/project-cves
  returns: CVEs filed against the repository's own code, newest first: severity, CVSS, EPSS, exploit types, link_kinds (commit, pull, compare, releases, security_advisory, issues), a short description (severity=, exploit=, sort=published_date|cvss_score|epss_score and cursor narrow and page)
- GET https://api.securitycontext.com/v1/organizations/vercel/risk
  returns: risk summary, entry points and a fix plan across the organization
- GET https://api.securitycontext.com/v1/organizations/vercel/contributors
  returns: staff, pushers and committers with a credential leak
- GET https://api.securitycontext.com/v1/organizations/vercel/secret-leaks
  returns: secret-leak counts by status and severity
- GET https://api.securitycontext.com/v1/packages/npm/lodash/advisories
  returns: every advisory for the package with affected and fixed versions
- GET https://api.securitycontext.com/v1/packages/npm/lodash/maintainers
  returns: maintainers with credential-leak flags
- GET https://api.securitycontext.com/v1/libraries/libheif/advisories
  returns: the library's bug history from the per-repository and distro feeds
- GET https://api.securitycontext.com/v1/libraries/libheif/timeline
  returns: advisories per year and the memory-safety share
- GET https://api.securitycontext.com/v1/libraries/libheif/security-fixes
  returns: confirmed historical security fixes in libheif's own upstream code: commit, date, class, CWE, severity, files, linked advisories
- GET https://api.securitycontext.com/v1/products/f5/nginx/advisories
  returns: every CVE naming the product with NVD's affected ranges, newest first (sort=severity|cvss_score|epss_score; cursor pages on)

### lists by relation

- GET https://api.securitycontext.com/v1/repositories?cve=CVE-2021-44228
  returns: repositories exposed to that CVE; each row has a match block (package, version, runtime, fixed_version, evidence_url)
- GET https://api.securitycontext.com/v1/repositories?advisory=GHSA-4xc9-xhrj-v574
  returns: the same for one advisory id
- GET https://api.securitycontext.com/v1/packages?advisory=MAL-2024-5247
  returns: the packages a malicious-package advisory (MAL-…, GHSCAN-MAL-… or an alias) names, indexed or not
- GET https://api.securitycontext.com/v1/repositories?package=npm/lodash
  returns: repositories that depend on the package, any version
- GET https://api.securitycontext.com/v1/repositories?package=npm/lodash@4.17.20
  returns: repositories pinned to exactly that version
- GET https://api.securitycontext.com/v1/repositories?library=libheif@1.20.2
  returns: repositories that ship that native library build through any carrier package
- GET https://api.securitycontext.com/v1/repositories?library=libheif&bundled_in=npm/sharp
  returns: repositories that get the library through one named carrier
- GET https://api.securitycontext.com/v1/repositories?upstream=facebook/react
  returns: repositories that depend on a package built from that repository
- GET https://api.securitycontext.com/v1/repositories?library=libheif&context=product
  returns: the same kind of list restricted to rows declared outside test, example, benchmark, docs and tooling paths; context=test shows the fixture-only ones
- GET https://api.securitycontext.com/v1/repositories?cve=CVE-2021-44228&signal=high
  returns: only the high-signal matches: the advisory applies, the dependency is not just build tooling, it is declared in product code, and the repository is not archived, a template, a sample or research code; total_unfiltered gives the count without these rules
- GET https://api.securitycontext.com/v1/packages?used_by=facebook/react
  returns: what the repository depends on
- GET https://api.securitycontext.com/v1/packages?repository=facebook/react
  returns: packages published from the repository
- GET https://api.securitycontext.com/v1/packages?cve=CVE-2021-44228
  returns: packages with a version affected by the CVE
- GET https://api.securitycontext.com/v1/products?cve=CVE-2021-44228
  returns: the NVD products the CVE names, each match block with NVD's affected ranges and whether only on a platform
- GET https://api.securitycontext.com/v1/repositories?cve=CVE-2023-4863&include=history&limit=5
  returns: who is exposed to the CVE, plus one history block: its current exploitation context and NVD status and every change logged for it (KEV added, severity, EPSS, public exploits)

### lists by attribute

- GET https://api.securitycontext.com/v1/repositories?finding=known_exploited_runtime&severity=critical&sort=stars
  returns: repositories whose runtime dependencies include a CISA-KEV CVE, most popular first (finding=malicious_package works the same way and may be empty on a clean index)
- GET https://api.securitycontext.com/v1/repositories?exploit=public_exploit&min_stars=10000&sort=stars
  returns: popular repositories with an applicable advisory whose CVE has a public exploit (exploit=known_exploited|vulncheck_known_exploited|nuclei_template work the same way; packages and organizations take exploit= too)
- GET https://api.securitycontext.com/v1/repositories?min_stars=50000&pushed_since=2026-06-01
  returns: large, recently active repositories
- GET https://api.securitycontext.com/v1/repositories?organization=vercel&sort=risk_score
  returns: one organization's repositories, riskiest first
- GET https://api.securitycontext.com/v1/organizations?company=Vercel
  returns: every GitHub owner that belongs to the company
- GET https://api.securitycontext.com/v1/organizations?finding=active_secret_leak&sort=stars
  returns: organizations with a still-valid leaked secret, by reach
- GET https://api.securitycontext.com/v1/packages?ecosystem=pypi&severity=critical&sort=dependents
  returns: the most-depended-on PyPI packages with a critical advisory
- GET https://api.securitycontext.com/v1/libraries?input_facing=true&sort=score
  returns: native libraries that parse attacker-controlled input, ranked by research score
- GET https://api.securitycontext.com/v1/libraries?unmined=true
  returns: widely shipped input-facing libraries with almost no advisory history
- GET https://api.securitycontext.com/v1/products?exploit=known_exploited&sort=known_exploited_cves
  returns: NVD products with the most CISA known-exploited CVEs (exploit=public_exploit|nuclei_template work the same way)
- GET https://api.securitycontext.com/v1/cves?vendor=apache&severity=critical&exploit=nuclei_template
  returns: critical Apache CVEs that have a nuclei template, newest first
- GET https://api.securitycontext.com/v1/cves?q=prototype+pollution&sort=epss_score&facets=year
  returns: keyword search over CVE descriptions and NVD product names, most likely exploited first, counted by year
- GET https://api.securitycontext.com/v1/cves?exploit=known_exploited&published_since=2026-01-01&indexed=true
  returns: CISA known-exploited CVEs published this year that reach at least one indexed repository or package
- GET https://api.securitycontext.com/v1/cves?oss=true&exploit=known_exploited&sort=cvss_score
  returns: known-exploited CVEs in open-source code (filed against a project, or reached through a package), highest CVSS first; each row has oss and the number of projects it was filed against

### shaping

- GET https://api.securitycontext.com/v1/repositories?severity=critical&limit=100&sort=stars
  returns: a full page of 100; the response's cursor continues it: append &cursor=<value>
- GET https://api.securitycontext.com/v1/repositories?facets=severity,finding&limit=1
  returns: counts per severity and per finding type over the whole result set
- GET https://api.securitycontext.com/v1/packages?used_by=facebook/react&fields=package,worst_severity&limit=100
  returns: only those fields per row

### scans

- GET https://api.securitycontext.com/v1/scans?repository=facebook/react
  returns: the repository's most recent scan jobs, newest first: id, status (queued, running, done, failed), step, times, error; no result (open a job by its id for that). POST /v1/scans with {"repository": "owner/name"} queues a scan; GET /v1/scans/{id} follows it and carries the result once status is done

### what errors look like

- GET https://api.securitycontext.com/v1/repositories/no-such-owner/no-such-repo
  returns: 200 with found:false and up to 5 candidates; never a 404 for an unknown name
- GET https://api.securitycontext.com/v1/repositories?bogus=1
  returns: 400 listing the accepted parameter names
- GET https://api.securitycontext.com/v1/packages?finding=malicious_package
  returns: 400: finding= is a repository/organization filter; for packages use the lookup's malicious flag or /v1/repositories?finding=malicious_package
- GET https://api.securitycontext.com/v1/index
  returns: the 11th anonymous call in a minute answers 429 with Retry-After (code rate_limited) and higher_limits: https://neo.projectdiscovery.io

## Vocabulary

Finding types:
- malicious_package: depends on a package listed in the malicious-package catalog (OSV MAL-*)
- known_exploited_runtime: a runtime dependency is on a version affected by a CVE in the CISA Known Exploited Vulnerabilities catalog
- reported_exploited_runtime: a runtime dependency that applies is on a version affected by a CVE that VulnCheck lists as exploited (not CISA), and it passes three gates: CVSS 7 or more, at least two independent report sources behind VulnCheck's entry (scanner dashboards and honeypot hits do not count), and an affected project that is used and active (1,000+ GitHub stars, or 100+ dependent repositories in the index, pushed within two years); only in a repository that is not low signal. Severity high like known_exploited_runtime, half its risk weight
- active_secret_leak: a secret committed to the repository was still valid when checked
- leaked_push_access: a person with push access has a GitHub credential in a public leak
- upstream_findings: a dependency's own upstream repository carries one of the findings above
- known_exploited_project_cve: a CVE filed against the repository's own code (a project CVE) is in the CISA KEV catalog. It adds nothing to risk_score or severity: most project CVEs are fixed at HEAD, so see /project-cves and the fix dates before reading it as an open hole

Exploit types (exploit=):
- known_exploited: the CVE is in the CISA Known Exploited Vulnerabilities catalog
- vulncheck_known_exploited: the CVE is in VulnCheck's KEV list (broader than CISA's)
- public_exploit: a public exploit or proof of concept exists (PoC-in-GitHub, Metasploit, VulnCheck XDB, NVD exploit references)
- nuclei_template: ProjectDiscovery's nuclei-templates has a detection template for the CVE

Severities: critical, high, medium, low, none
Ecosystems: npm, pypi, maven, go, cargo, rubygems, composer, nuget, other

Key terms:
- findings: the list of finding types present; `finding_types` is the same as names, `findings` carries counts
- severity: worst finding severity for the object (critical > high > medium > low > none). A runtime dependency with a public exploit for an applicable CVE makes a repository medium at least (counts.public_exploit_vulns)
- risk_score: 0-100 sort key combining findings, reach and staleness; `risk_percentile` places it in the index
- known_exploited: the CVE is in the CISA KEV catalog; `_runtime` means it reaches a runtime dependency
- epss_score: EPSS probability of exploitation in the next 30 days
- exploitation: on every advisory with a CVE: known_exploited (CISA KEV) + known_exploited_since, known_exploited_by (every KEV list that has it: cisa, vulncheck) + vulncheck_known_exploited_since, exploitation_seen (exploitation reported in the wild), public_exploit + public_exploit_count + public_exploit_first_date, nuclei_template {id, url} (the detection template), remote and authentication_required (from the CVSS vector), hackerone_reports (HackerOne reports filed for the CVE), exposed_hosts (internet-facing hosts running an affected product, per Shodan). null when the index has no record of the CVE
- nvd_status: on every advisory with a CVE: NVD's own status (analyzed, modified, awaiting_analysis, undergoing_analysis, received, deferred, rejected); null = not in NVD
- rejected_by_nvd: NVD rejected the CVE (rejected_reason says why). The advisory is still listed when GitHub or the upstream keeps it: report it as rejected by NVD, never as a confirmed vulnerability
- history: include=history on a list filtered by cve= (repositories, packages, organizations, libraries): one `history` block for that CVE: its current nvd_status and exploitation plus history_since and changes (its timeline, oldest first). include=history on /advisories (packages and libraries): each advisory's change timeline, oldest first: changed_date, field (vuln_status, severity, cvss_score, cvss_vector, cwe, is_patch_available, cisa_kev_added, cisa_ransomware, vulncheck_kev_added, epss_score / epss_percentile when they move past a threshold, poc_count, is_exploit_seen, nuclei_templates, h1_reports, exposure_max_hosts), source, old_value, new_value. The log starts at _meta.history_since; [] = nothing changed since
- recent_changes: on /v1/index: what changed for the index's CVEs in the last 7 days of the change log: newly known exploited (CISA), newly on VulnCheck's list, a first public exploit, a first nuclei template, rejected by NVD, raised to critical; CVE counts with the indexed repositories each touches
- nvd_products: on a library lookup: the library's NVD products (vendor:product) with NVD's catalog for each: CVE counts by severity, CISA known-exploited, public exploits, nuclei templates, exposed hosts (Shodan), a 0-100 product score (severity, exploitation and exposure), first, last and latest CVE
- product: an NVD product, vendor:product as NVD writes it, lower case, without CPE escapes (joomla:joomla!). Its CVEs are those whose vulnerable configuration rows name it; counts (cves, critical, high, known_exploited_cves, public_exploit_cves, nuclei_template_cves) are over those CVEs, score is the catalog's 0-100 formula on them plus Shodan exposure
- cve_record: /v1/cves/{cve}: what vuln-intel holds for the CVE. known_exploited_entries lists every KEV entry (cisa, vulncheck) with added and due dates and ransomware use; references carry NVD's tags (capped at 100, references_total counts all); public_exploits are links to exploits and proofs of concept (the first 50; the dataset keeps at most 100 per CVE, so public_exploits_capped true means public_exploits_total is a floor); products are the NVD products whose vulnerable configurations name it (capped at 100); index counts the repositories (all and high signal) and packages in the index exposed to it. A CVE NVD has not analysed yet has a description but no products
- basis: on a product version's advisories, why the CVE affects that version: version_list (NVD itself lists the version under the CVE's rule), exact_version (the rule names that exact version), range (inside NVD's range by the API's own version comparison, used where NVD has no list: a product or version missing from NVD's dictionary), all_versions (the rule names no version at all). undetermined lists the CVEs whose rule could not be compared (a date-shaped bound, a version string with no number): report them as unknown, never as affected or safe. platforms, when present, is the condition NVD attaches (only on that operating system or with that other product)
- exploit: exploit= on repository, organization and package lists: an advisory (that applies to the repository; on the high basis also high signal) whose CVE has that exploit type. See exploit_types
- evidence_url: the manifest line, commit or record that proves the row; present on every finding except secret leaks
- declared_in: the manifest or lockfile path inside the repository that the evidence points at
- context: where that manifest lives: product, test, example, benchmark, docs or tooling. A path rule only: a monorepo's root lockfile is product even when the entry comes from an internal workspace app, because the index does not yet record which workspace package pulls a dependency. Report the context with every exposure and never present a test, example, benchmark, docs or tooling row as what the project ships
- advisory_url: the canonical advisory record (OSV, GHSA, NVD)
- bundled_in: the carrier package whose artifact contains a native library, e.g. npm/sharp for libheif
- upstream: the source repository a package is built from
- match: on filtered lists, the block that says why the row matched: package and version, runtime, bundled_in, fixed_version, evidence_url, and (where the dataset has them) context, applicable and applicability_reason
- signal: signal=high narrows any list, lookup or /v1/index to high-signal findings; signal=all (the default) is the unfiltered index. See conventions
- applicable: false when a matched advisory does not apply to how the repository uses the package: see applicability_reason
- applicability_reason: why a row does not apply: component_scoped (the CVE lives in a component of the package the repository does not use, or needs the repository to run the package's own server and it is not a direct dependency), go_import_not_used (the repository's Go code imports none of the vulnerable packages, or no package of the module at all), shadowed_by_direct (a nested npm copy while the direct dependency on the same package is on an unaffected release), before_affected_code (the version predates the code the advisory is about, per a reviewed lower bound), built_from_source (the advisory is in a bundled binary the repository does not use: every Dockerfile builds the package from source), build_tooling
- build_tooling: the dependency is only reached through build tools (webpack loaders, babel, vite, jest, ...): installed on a developer or CI machine, never shipped
- project_cves: on a repository: the CVEs filed against its own code, where the repository is the place the fix lands, as opposed to the advisories it inherits from the packages it uses (a project is an ordinary repository, indexed or not). The lookup carries a summary {total, critical, high, known_exploited, last_12_months, newest, newest_cve}, null = none; /v1/repositories/{owner}/{name}/project-cves lists them with link_kinds (how the CVE points at the repository: commit, pull, compare, releases, security_advisory, issues). A project CVE has no weight in risk_score and does not change severity. /v1/cves/{id} lists the projects a CVE was filed against (`projects`, each with `indexed`). A CVE NVD rejected is not counted
- dependencies: on a repository: the packages it uses that have advisories or are malicious, not every package it uses (counts.vulnerable_dependencies, dependencies_total and include=dependencies, and /v1/packages?used_by=, hold only those); scan.dependencies counts every package the scan found. A package missing from the list is not proof the repository does not use it
- dependency_scan: on a repository lookup and list item: ok, no_manifest (no dependency manifest found) or no_dependencies (a manifest that declares none). In the last two every dependency count (counts, dependencies_total, risk_score) is 0 because nothing was scanned: it does not say the repository is clean
- oss: on a CVE: true when it is in open-source code (filed against a project, or reached through a package), false when the classification found neither, null when the dataset has no classification; /v1/cves?oss=true|false filters on it. `projects` on a CVE list item is the number of projects the CVE was filed against
- capability: what a repository's own code can do, read from the packages it declares directly (never transitive ones): http_server, outbound_http, headless_browser, file_upload, templating, deserialization, xml_parsing, archive_extraction, shell_exec, sql, auth_tokens, model_loading, llm_agent; each comes with the vulnerability classes it brings (outbound_http: server-side request forgery). /v1/repositories?capability= lists the repositories with one, and a comma list (capability=http_server,deserialization) those with all of them; attack_surface.capabilities shows a repository's. The standard library (pickle, subprocess, net/http) is not seen, and having a capability does not mean untrusted input reaches it
- attack_surface: on a repository: where it is exposed, from what the index holds, computed per request. capabilities: [{capability, classes, packages, runtime_product}] what its code can do (see capability). inputs: the untrusted input its bundled native parsers decode, by kind ({kind, formats, libraries, runtime_product: one ships at runtime in product code, seen_in_artifact: false = only inferred from a package that bundles it}); weak_spots: where its own bugs land (fix_classes, recurring_files fixed more than once, silent_fixes with no public advisory, fixes_last_12_months, own_cves), null = no fix history and no CVEs of its own, which is unknown, not clean; who_can_change: contributors_with_leak, contributors_with_write_access, leaked_push_access, active_secret_leaks, upstream_maintainers_with_leak, dependencies_with_upstream_findings, malicious_package; reach: published_packages, dependents, dependents_runtime, top_packages. Indicators, not a threat model: the index sees what a project bundles and who can change it, not how it is deployed or whether its code reaches a parser
- security_fixes: on a repository, and on a native library (its upstream's): the history of confirmed security fixes in its own code (commits analysed, fixes, first and last fix date, by severity, top classes). Each fix's severity is its linked CVE's when one is known (severity_basis advisory), otherwise the classifier's estimate (severity_basis estimate, never above high; severity_estimated counts them); fix_basis says who decided that the commit is a security fix: classifier (the code change was confirmed) or advisory (an advisory names the commit as its fix, and the classifier did not confirm the code change); tool_only marks a fix that touched only tooling (tools/, contrib/, examples/ ...). A library shows its upstream's library-code fixes only: tool-only fixes and, for a fork, the parent's commits it inherited are left out and counted under excluded. null = not analysed; fixes 0 = none found in the history read, not proof of no flaws. The analysis reads recent history, so dates skew recent. A past fix is evidence of an attack surface someone found and closed, not an open vulnerability
- low_signal: a repository that is archived, a GitHub template, a sample/demo/tutorial (by name, owner, topic or description), research (paper) code, deprecated per its own description, or stale (scanned commit over two years old and under 1,000 stars); `reasons` says which. Its findings stay listed on signal=all; signal=high leaves it out
- severity_label: GitHub's own severity label for a GitHub-reviewed advisory (null for others); `cvss3_score` is the CVSS base score from ProjectDiscovery's CVE dataset when the advisory has a CVE, else GitHub's v3.1 score; `severity` is the label capped by that score's band (the band alone when there is no label), so critical and high mean both agree
- cvss3_score: the advisory's CVSS v3.1 base score, computed from its vector
- risk_score_signal: risk_score with its dependency terms counted on the high-signal basis only; signal=high shows it as risk_score (and sorts by it) with the unfiltered value under `unfiltered`
- in_scope: 1,000+ stars or risk score 60+; counts labelled `_in_scope` use it, everything else counts the whole index
- email_masked: a***z@domain; people are identified by github_username plus this, never a raw address

## Conventions

- Every route is a GET that returns JSON, except POST /v1/scans (queue a scan); all data lives under /v1.
- Start with /v1/index (dataset date, scope, counts) and /v1/tools (every endpoint as a JSON-schema function definition, ready to hand to a model as its tool list).
- A lookup of an unknown name answers 200 with found:false and up to 5 candidates; never a dead end. Names are case-insensitive.
- Lists carry count, total, truncated and cursor; pass cursor= to continue. limit= defaults to 25, at most 100.
- Sub-sections added with include= are capped at 50 rows each, with a total and a link to the full list.
- Responses are capped at 256 KB; a capped list says truncated:true and gives a cursor.
- Cross-noun questions are list filters with one grammar: cve=, advisory=, package=eco/name[@version], library=name[@version], bundled_in=, upstream=, used_by=, repository=. At most one of cve/advisory/package/library/upstream per call; library= and bundled_in= combine. /v1/products takes cve= (the products NVD names for it).
- facets=a,b (at most 3) adds counts per value; fields=a,b trims a response; sort= takes the noun's sort keys, descending.
- Unknown query parameters or values are a 400 whose body lists the accepted names.
- Add .md to any GET path for the same answer as Markdown (/v1/repositories/{owner}/{name}.md is the repository's security context: everything the index knows about it). Same query parameters, same data, rendered as headings, lists and tables.
- Every response carries _meta (dataset date, index counts, the note above) and _links (index plus the lists this object leads to). Responses carry an ETag; send If-None-Match to get a 304.
- Every row with an evidence_url also carries declared_in (the manifest path) and context (product, test, example, benchmark, docs, tooling); context= narrows a relation filter to one of them. The index records the lockfile, not the workspace package that pulled an entry, so do not explain why a version is present beyond what declared_in shows.
- signal= (high|all, default all) picks the basis. signal=high drops low-signal repositories (archived, template, sample, research, deprecated, stale) from lists, facets and totals, keeps only relation rows that apply, are not build tooling and are declared in product code (or have no file evidence), and shows risk_score, finding_types and findings on the high-signal basis with the unfiltered values under `unfiltered`. A high list adds total_unfiltered, the signal=all total of the same query, so nothing is hidden silently. Lookups carry a `signal` block (low_signal, reasons, archived, template, sample, research, stale) on both bases.
- Scan jobs (/v1/scans) change while they run: they are never cached and carry no ETag. Poll GET /v1/scans/{id} until status is done or failed.
- People appear as github_username plus a masked e-mail only; secret leaks carry no file location and no secret value.
- Being listed means exposed, not breached: a finding says what an object is exposed to, never that it was compromised.
- A repository relates to a CVE in two directions; never read one as the other. Through its dependencies (it uses an affected package or bundled library): /v1/repositories?cve=, counts.vulnerable_dependencies, include=dependencies, and a CVE's `repositories` count and `index`. In its own code (it is the project where the fix lands): `project_cves`, /v1/repositories/{owner}/{name}/project-cves, and a CVE's `projects`. A repository with 0 vulnerable dependencies can have hundreds of project CVEs, and most project CVEs are already fixed at HEAD.

## What this is not

- not threat intelligence: no attribution, no actors, no incident data
- not breach data: no passwords, no secret values, no raw e-mail addresses
- not a live scanner: the index is rebuilt from public repositories on a schedule; /v1/index says when. A scan job (POST /v1/scans) covers one repository you name
- not exhaustive: the index covers public GitHub repositories that were scanned, not all of GitHub

## Errors

- 400: unknown or invalid query parameter or value; the body lists the accepted names
- 404: unknown route (an unknown name on a known route is a 200 with found:false)
- 429: rate limit (code rate_limited); body has limit, window_seconds, retry_after_seconds, higher_limits (https://neo.projectdiscovery.io)
- 503: overloaded worker; retry after a moment
