Shell and jq recipes
Short recipes for the terminal and for CI scripts. They need curl and jq 1.6 or later. The first three work without an API key; the rest read your key from DEVSECURE_API_KEY.
export DEVSECURE_API=https://api.intelligence.devsecure.io
export DEVSECURE_API_KEY=... # from your dashboard; never commit it
Look up one CVE (no key)
curl -s "$DEVSECURE_API/api/v1/public/cve/CVE-2024-3400" \
| jq '{cve: .data.cve_id, rps: .data.rps.score, final_priority: .data.rps.band, rule: .data.rps.band_basis, in_kev: .data.kev.in_catalog, data_as_of}'
final_priority is the band after the KEV floor and the EPSS gate; rule says which one set it (rps, kev_floor or epss_gate). See Priority bands.
The CISA KEV catalogue, ranked (no key)
The ten highest-ranked KEV entries as a table:
curl -s "$DEVSECURE_API/api/v1/kev?limit=10" \
| jq -r '.results[] | [.rps_score, .cve_id, .kev.vendor_project, .kev.product] | @tsv'
KEV entries CISA marks as used in ransomware, highest RPS first:
curl -s "$DEVSECURE_API/api/v1/kev" \
| jq -r '.results[] | select(.kev.ransomware_associated == true) | [.rps_score, .cve_id, .kev.vulnerability_name] | @tsv' \
| head -20
The full catalogue is about 1.5 MB and cached for an hour, so fetch it at most hourly.
Totals for a dashboard (no key)
curl -s "$DEVSECURE_API/api/v1/stats" | jq '.data'
Rank a CVE list
Put one CVE ID per line in cves.txt, then:
jq -R -s '{cve_ids: (split("\n") | map(select(length > 0)))}' cves.txt \
| curl -s -X POST "$DEVSECURE_API/api/v1/prioritize" \
-H "Authorization: Bearer $DEVSECURE_API_KEY" \
-H "Content-Type: application/json" \
-d @- \
| jq -r '.ranked[] | [.rank_in_request, .cve_id, .priority_band, .rps_score, .reason] | @tsv'
Rank a scanner's findings
Any scanner report that mentions CVE IDs works: Trivy, Grype, SARIF, CycloneDX or plain text.
grep -ohE 'CVE-[0-9]{4}-[0-9]{4,}' scan-report.json | sort -u > cves.txt
Then rank cves.txt as above. For the full job (thresholds, allowlists, VEX and a job summary), use the CI gate.
Stay within the per-call limit
Prioritize takes up to 25 IDs per call on Free and 1,000 on Pro and above. This sends cves.txt in chunks of 25 and joins the results into one ranked list:
jq -R -s -c 'split("\n") | map(select(length > 0)) | _nwise(25) | {cve_ids: .}' cves.txt \
| while read -r body; do
curl -s -X POST "$DEVSECURE_API/api/v1/prioritize" \
-H "Authorization: Bearer $DEVSECURE_API_KEY" \
-H "Content-Type: application/json" \
-d "$body"
done \
| jq -s -r 'def rank: {critical_priority: 0, high_priority: 1, medium_priority: 2, low_priority: 3, informational: 4}[.priority_band] // 5;
[.[].ranked[]] | sort_by([rank, -.rps_score]) | .[] | [.cve_id, .priority_band, .rps_score] | @tsv'
The merge sorts the way the API does: by Final Priority first, then by RPS within a band (a CISA KEV CVE floored at High stays above a Medium with a higher score). CVEs not found come last. Each CVE found counts once against your monthly allowance. See Batch and pagination.
Fail a CI step on High, Critical or KEV
jq -e exits non-zero when the result is false, so this step fails if any CVE is High or Critical, or listed in CISA KEV:
jq -R -s '{cve_ids: (split("\n") | map(select(length > 0)))}' cves.txt \
| curl -s -X POST "$DEVSECURE_API/api/v1/prioritize" \
-H "Authorization: Bearer $DEVSECURE_API_KEY" \
-H "Content-Type: application/json" \
-d @- > ranked.json
jq -r '.ranked[] | select(.priority_band == "critical_priority" or .priority_band == "high_priority" or .evidence.kev.listed == true) | "\(.cve_id)\t\(.priority_band)\t\(.reason)"' ranked.json
jq -e '[.ranked[] | select(.priority_band == "critical_priority" or .priority_band == "high_priority" or .evidence.kev.listed == true)] | length == 0' ranked.json > /dev/null
Your organisation decides what blocks a build; change the bands to match your policy.
What changed in the last 24 hours
KEV additions and priority rises from the movers feed:
curl -s "$DEVSECURE_API/api/v1/movers?window=24h&type=kev_added,priority_change" \
-H "Authorization: Bearer $DEVSECURE_API_KEY" \
| jq -r '.data.items[] | select(.type == "kev_added" or .direction == "up") | [.occurred_on, .cve_id, .type, (.priority_now // ""), .reason] | @tsv'
Check your remaining allowance
curl -s -D - -o /dev/null "$DEVSECURE_API/api/v1/cve/CVE-2021-44228" \
-H "Authorization: Bearer $DEVSECURE_API_KEY" \
| grep -i '^x-\(quota\|ratelimit\)-'
X-Quota-Remaining is what's left of the monthly allowance; X-RateLimit-Remaining is what's left this minute. A 429 with code rate_limited comes with Retry-After (seconds to wait); quota_exceeded means the month's allowance is used. See Error handling.
This product uses the NVD API but is not endorsed or certified by the NVD. CVE is a trademark of The MITRE Corporation. All third-party sources and licences: Data Sources and Licences.