GitHub Advisories Scraper: GHSA Security Database
Pricing
from $0.74 / 1,000 advisory scrapeds
GitHub Advisories Scraper: GHSA Security Database
Scrape the GitHub Advisory Database: GHSA identifiers, CVE aliases, severity, affected package ranges, patched versions and CWEs. Curated and often ahead of NVD.
Pricing
from $0.74 / 1,000 advisory scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
5 days ago
Last modified
Categories
Share

GitHub Advisories Scraper exports the GitHub Advisory Database as structured records, GHSA identifier, CVE alias, severity, CVSS score and vector, CWE list, every affected package with its vulnerable version range and first patched version.
GitHub reviews and publishes advisories itself, often days before the same finding lands in NVD, and it maps each one to concrete package ranges rather than free-text product names. This Actor reads GitHub's published advisory data directly: no browser, no proxies, no login required. A token is optional and only raises the request budget.
Agent skill: SKILL.md
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/github-advisories-scraper.md
What you get
| Output field | Meaning |
|---|---|
ghsaId, cveId | GitHub's advisory ID and the CVE it maps to (null when no CVE has been assigned yet) |
summary, description | One-line title and the full Markdown write-up: impact, patches, workarounds |
severity | critical, high, medium, low or unknown |
cvssScore, cvssVector, cvssVersion | Base score, the full vector string, and which CVSS revision it came from |
cweIds | Every CWE the advisory is classified under, e.g. ["CWE-94", "CWE-306"] |
ecosystem, packageName | The primary affected package, registry and name |
vulnerableVersionRange, firstPatchedVersion | The exact affected range and the version that fixes it |
affected | Every affected package, not just the primary one, see the note below |
publishedAt, updatedAt | Advisory timestamps |
references | External links: patches, issues, vendor bulletins |
url | The human-readable advisory page on github.com |
scrapedAt | Run timestamp |
A RUN_SUMMARY record in the key-value store holds per-run counts, remaining rate-limit budget, the filters used, and any sweep that failed.
On affected. One advisory routinely covers several packages, GHSA-r5fr-rjxr-66jc alone lists lodash, lodash-es, lodash-amd and lodash.template. The dataset row stays flat and one-per-advisory, so the scalar ecosystem / packageName / vulnerableVersionRange / firstPatchedVersion fields describe the primary entry, and affected carries the complete list. When you set affectsPackage, the primary is the entry for that package, so the scalar fields say what you asked about.
Common use cases
Track advisories for your dependency set. Sweep only the ecosystems you actually ship, on a schedule, and diff on ghsaId.
{"ecosystems": ["npm", "pip", "go"],"publishedFrom": "2026-07-01","maxResults": 1000}
Cross-reference GHSA against NVD. Pull everything with a CVE alias and join on cveId to spot findings GitHub has published and NVD has not yet enriched.
{"severities": ["critical", "high"],"publishedFrom": "2026-01-01","maxResults": 2000}
Feed a security alerting workflow. Watch one package and alert whenever a new ghsaId appears for it.
{"affectsPackage": "lodash","ecosystems": ["npm"]}
Quick start
Everything new and serious, across every ecosystem:
{"severities": ["critical", "high"],"publishedFrom": "2026-01-01"}
Everything, with a token so the 60/hour ceiling stops mattering:
{"ecosystems": ["npm", "pip", "maven", "go"],"publishedFrom": "2025-01-01","githubToken": "ghp_your_token_here","maxResults": 20000}
Input
| Field | Type | Default | Notes |
|---|---|---|---|
ecosystems | array | [] | npm, pip, rubygems, maven, nuget, composer, go, rust, erlang, actions, pub, swift, other. Empty = all ecosystems in one sweep. |
severities | array | [] | critical, high, medium, low, unknown. moderate is accepted and normalised to medium. Empty = all. |
affectsPackage | string | "" | Exact registry package name, e.g. lodash, django, org.apache.commons:commons-text. |
publishedFrom | string | "" | YYYY-MM-DD. Advisories published on or after this date. |
githubToken | string | "" | Optional PAT. Raises 60 → 5000 requests/hour. Stored as a secret. |
maxResults | integer | 500 | Cap across all sweeps. 0 = no cap. |
Which combinations make sense. ecosystems and severities are the two filters GitHub applies server-side one value at a time, so the Actor fans them out: three ecosystems × two severities is six separate paginated sweeps, each burning its own rate-limit budget. Unauthenticated. That is realistically the whole hourly allowance. If you want breadth, prefer a single broad sweep with publishedFrom and filter afterwards; if you want depth on one ecosystem, narrow with severities. affectsPackage and publishedFrom are free. They are applied inside the same request.
Output example
{"ghsaId": "GHSA-r5fr-rjxr-66jc","cveId": "CVE-2026-4800","summary": "Prototype pollution in lodash template compilation","description": "### Impact\n\nThe template compiler …","severity": "high","cvssScore": 8.1,"cvssVector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","cvssVersion": "3.1","cweIds": ["CWE-1321"],"ecosystem": "npm","packageName": "lodash","vulnerableVersionRange": ">= 4.0.0, <= 4.17.23","firstPatchedVersion": "4.18.0","affected": [{ "ecosystem": "npm", "packageName": "lodash", "vulnerableVersionRange": ">= 4.0.0, <= 4.17.23", "firstPatchedVersion": "4.18.0" },{ "ecosystem": "npm", "packageName": "lodash-es", "vulnerableVersionRange": ">= 4.0.0, <= 4.17.23", "firstPatchedVersion": "4.18.0" },{ "ecosystem": "npm", "packageName": "lodash.template", "vulnerableVersionRange": ">= 4.0.0, < 4.18.0", "firstPatchedVersion": "4.18.0" }],"publishedAt": "2026-04-01T23:51:12Z","updatedAt": "2026-04-02T14:02:55Z","references": ["https://github.com/lodash/lodash/security/advisories/GHSA-r5fr-rjxr-66jc","https://nvd.nist.gov/vuln/detail/CVE-2026-4800"],"url": "https://github.com/advisories/GHSA-r5fr-rjxr-66jc","scrapedAt": "2026-08-06T12:00:00.000Z"}
RUN_SUMMARY in the key-value store:
{"sweepsRequested": 2,"sweepsFailed": 0,"failures": [],"advisoriesSaved": 500,"requestsUsed": 5,"rateLimited": false,"rateLimit": {"limit": 60,"remaining": 43,"resetsAt": "2026-08-06T13:12:11.000Z","authenticated": false},"filters": {"ecosystems": ["npm"],"severities": ["critical", "high"],"affectsPackage": null,"publishedFrom": "2026-01-01","maxResults": 500},"finishedAt": "2026-08-06T12:00:04.918Z"}
Limits and behaviour
- 60 requests per hour, per IP, unauthenticated. This is the single constraint that matters. Advisories page at 100 per request, so an unauthenticated run can retrieve about 6,000 advisories per hour at absolute best. A token lifts the budget to 5000 requests/hour, roughly 500,000 advisories, and it is the difference between this Actor being a toy and being usable at scale.
- The budget is read from every response. rate-limit headers and rate-limit headers are logged after each sweep and written into
RUN_SUMMARY.rateLimit. - Exhaustion stops the run cleanly. When the budget hits zero the Actor stops, logs the reset time, sets
RUN_SUMMARY.rateLimited: true, and keeps everything it already saved. It does not hammer into a wall of 403s. - Multiple selections multiply cost. The API takes one ecosystem and one severity per request, so N ecosystems × M severities is N×M paginated sweeps.
- One failing sweep never aborts the run. Errors land in
RUN_SUMMARY.failuresand the next sweep starts. The Actor only throws if every sweep failed. - Transient errors are retried. 429 and 5xx get three attempts with linear backoff. A 422 (bad filter value) is fatal and reported immediately, because retrying it would only burn budget.
- Duplicates are removed. When sweeps overlap, an advisory is saved once, keyed on
ghsaId. - Public data only. No authentication is required, no personal data is collected, no access control is bypassed.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~github-advisories-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"ecosystems": ["npm"],"severities": ["critical", "high"],"publishedFrom": "2026-01-01","maxResults": 200}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/github-advisories-scraper').call({ecosystems: ['npm', 'pip'],severities: ['critical'],publishedFrom: '2026-01-01',});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const a of items) {console.log(`${a.ghsaId} ${a.severity.padEnd(8)} ${a.packageName} → fixed in ${a.firstPatchedVersion}`);}
FAQ
Do I need a proxy? No. Proxy configuration is not required to run this Actor.
Do I need a GitHub account? Not to run it. You need one only if you want a token, which you almost certainly do for anything beyond a few hundred advisories.
What scopes does the token need? None. A classic PAT with zero scopes ticked, or a fine-grained token with read access to public repositories, is enough, the advisory database is public and the token is only there to identify you for rate-limiting.
Why is cveId sometimes null? GitHub publishes reviewed advisories as soon as they are triaged; the CVE is assigned separately and can lag by days. That gap is exactly why this data is worth pulling.
Why did I get fewer advisories than maxResults? Either the filter combination has fewer matches, or the rate limit was reached. RUN_SUMMARY distinguishes the two: rateLimited: true plus resetsAt tells you it was the budget.
What happens if GitHub is unavailable? 5xx responses are retried three times, then that sweep is recorded in RUN_SUMMARY.failures and the run continues with the next one.
Can I schedule it? Yes, it is designed for it. Set publishedFrom to the previous run's date and diff on ghsaId.
Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.