Using the Snyk API to find and fix vulnerabilities
Josh Emerson
3 janvier 2018
0 minutes de lectureIllustration by Lou Reade.
In this blog post, you will learn how to use the Snyk API to retrieve all the issues associated with a given project. There are several reasons you may find it valuable, notably pulling them into your reports and dashboards, giving management and developers visibility into their vulnerability status within the portals and workflows they’re already using.
Over the following steps, we will use the API to:
Fetch the list of organizations you have access to
Fetch all projects under an organization
Fetch the list of issues for your projects
Prerequisites
The Snyk API is available to customers on one of our paid plans. To get started with the API, log in or sign up for an account, and grab your API key from https://app.snyk.io. You can learn about all the endpoints exposed by the API at https://snyk.docs.apiary.io.
If you haven’t already created some projects, you can do so by running snyk monitor
via the Snyk command line tool, or you can add projects from various sources (such as GitHub, GitLab, and Heroku) via the website.
You’ll also want to copy your API key from https://snyk.io/account and use it everywhere you see below.
Fetching organisations
The first step is to use the organization’s endpoint at https://snyk.io/api/v1/orgs.
1curl --include \
2 --header "Content-Type: application/json; charset=utf-8" \
3 --header "Authorization: token <API_KEY>" \
4 'https://snyk.io/api/v1/orgs'
This will return a list of your organizations.
1{
2 "orgs": [
3 {
4 "name": "defaultOrg",
5 "id": "689ce7f9-7943-4a71-b704-2ba575f01089"
6 },
7 {
8 "name": "My Other Org",
9 "id": "a04d9cbd-ae6e-44af-b573-0556b0ad4bd2"
10 }
11 ]
12}
Fetching projects
Now take the ID of one that you wish to see project issues for and use it on the projects API endpoint at https://snyk.io/api/v1/org//projects (replace with the id your organization).
1curl --include \
2 --header "Content-Type: application/json" \
3 --header "Authorization: token <API_KEY>" \
4 'https://snyk.io/api/v1/org/<ORG_ID>/projects'
This will return a list of your projects.
1{
2 "org": {
3 "name": "defaultOrg",
4 "id": "689ce7f9-7943-4a71-b704-2ba575f01089"
5 },
6 "projects": [
7 {
8 "name": "atokeneduser/goof",
9 "id": "6d5813be-7e6d-4ab8-80c2-1e3e2a454545"
10 },
11 {
12 "name": "atokeneduser/clojure",
13 "id": "af127b96-6966-46c1-826b-2e79ac49bbd9"
14 }
15 ]
16}
Fetching project issues
Now that we have a list of projects we can fetch issues for any project we are interested in by hitting the issues endpoint as shown below, replacing with the ID of the project you want to a see a list of issues for:
1curl --include \
2 --request POST \
3 --header "Content-Type: application/json" \
4 --header "Authorization: token <API_KEY>" \
5 'https://snyk.io/api/v1/org/orgId/project/<PROJECT_ID>/aggregated-issues'
This will return a JSON response including an issues object containing an array of vulnerabilities and (if licenses are enabled for your organisation) an array of license issues that were found in the project when the last snapshot was taken.
The project issues API endpoint also supports filtering by issue type (vulnerability or license issue), severity (high, medium or low) and by whether the issue was ignored or patched. If we only wanted to see high severity vulnerabilities that are not patched or ignored we could make the following request:
1'https://snyk.io/api/v1/org/orgId/project/<PROJECT_ID>/aggregated-issues'curl --include \
2 --request POST \
3 --header "Content-Type: application/json" \
4 --header "Authorization: token <API_KEY>" \
5 --data-binary '{
6 "filters": {
7 "severities": [ "high" ],
8 "types": [ "vuln" ],
9 "ignored": false,
10 "patched": false
11 }
12 }' \
13 'https://snyk.io/api/v1/org/orgId/project/<PROJECT_ID>/aggregated-issues'
Now the response will not return any license issues, and will only show vulnerabilities that are high severity and have not been ignored or patched.
Using the response
Now that you have retrieved project issues, you will have a JSON payload as follows:
1{
2 "ok": false,
3 "issues": {
4 "vulnerabilities": [
5 {
6 "id": "npm:ms:20170412",
7 "url": "https://snyk.io/vuln/npm:ms:20170412",
8 "title": "Regular Expression Denial of Service (ReDoS)",
9 "type": "vuln",
10 "description": "## Overview\n[`ms`](https://www.npmjs.com/package/ms) is a tiny millisecond conversion utility.\n\nAffected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) due to an incomplete fix for previously reported vulnerability [npm:ms:20151024](https://snyk.io/vuln/npm:ms:20151024). The fix limited the length of accepted input string to 10,000 characters, and turned to be insufficient making it possible to block the event loop for 0.3 seconds (on a typical laptop) with a specially crafted string passed to `ms()` function.\n\n*Proof of concept*\n```js\nms = require('ms');\nms('1'.repeat(9998) + 'Q') // Takes about ~0.3s\n```\n\n**Note:** Snyk's patch for this vulnerability limits input length to 100 characters. This new limit was deemed to be a breaking change by the author.\nBased on user feedback, we believe the risk of breakage is _very_ low, while the value to your security is much greater, and therefore opted to still capture this change in a patch for earlier versions as well. Whenever patching security issues, we always suggest to run tests on your code to validate that nothing has been broken.\n\nFor more information on `Regular Expression Denial of Service (ReDoS)` attacks, go to our [blog](https://snyk.io/blog/redos-and-catastrophic-backtracking/).\n\n## Disclosure Timeline\n- Feb 9th, 2017 - Reported the issue to package owner.\n- Feb 11th, 2017 - Issue acknowledged by package owner.\n- April 12th, 2017 - Fix PR opened by Snyk Security Team.\n- May 15th, 2017 - Vulnerability published.\n- May 16th, 2017 - Issue fixed and version `2.0.0` released.\n- May 21th, 2017 - Patches released for versions `>=0.7.1, <=1.0.0`.\n\n## Remediation\nUpgrade `ms` to version 2.0.0 or higher.\n\n## References\n- [GitHub PR](https://github.com/zeit/ms/pull/89)\n- [GitHub Commit](https://github.com/zeit/ms/pull/89/commits/305f2ddcd4eff7cc7c518aca6bb2b2d2daad8fef)\n",
11 "from": [
12 "mongoose@4.2.4",
13 "mquery@1.6.3",
14 "debug@2.2.0",
15 "ms@0.7.1"
16 ],
17 "package": "ms",
18 "version": "0.7.1",
19 "severity": "low",
20 "language": "js",
21 "packageManager": "npm",
22 "semver": {
23 "unaffected": ">=2.0.0",
24 "vulnerable": "<2.0.0"
25 },
26 "publicationTime": "2017-05-15T06:02:45.497Z",
27 "disclosureTime": "2017-04-11T21:00:00.000Z",
28 "isUpgradable": true,
29 "isPatchable": true,
30 "identifiers": {
31 "CVE": [],
32 "CWE": [
33 "CWE-400"
34 ],
35 "ALTERNATIVE": [
36 "SNYK-JS-MS-10509"
37 ]
38 },
39 "credit": [
40 "Snyk Security Research Team"
41 ],
42 "CVSSv3": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
43 "cvssScore": 3.7,
44 "patches": [
45 {
46 "id": "patch:npm:ms:20170412:0",
47 "urls": [
48 "https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/develop/patches/npm/ms/20170412/ms_100.patch"
49 ],
50 "version": "=1.0.0",
51 "comments": [],
52 "modificationTime": "2017-05-16T10:12:18.990Z"
53 },
54 {
55 "id": "patch:npm:ms:20170412:1",
56 "urls": [
57 "https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/develop/patches/npm/ms/20170412/ms_072-073.patch"
58 ],
59 "version": "=0.7.2 || =0.7.3",
60 "comments": [],
61 "modificationTime": "2017-05-16T10:12:18.990Z"
62 },
63 {
64 "id": "patch:npm:ms:20170412:2",
65 "urls": [
66 "https://s3.amazonaws.com/snyk-rules-pre-repository/snapshots/develop/patches/npm/ms/20170412/ms_071.patch"
67 ],
68 "version": "=0.7.1",
69 "comments": [],
70 "modificationTime": "2017-05-16T10:12:18.990Z"
71 }
72 ],
73 "isIgnored": true,
74 "isPatched": false,
75 "upgradePath": [
76 "mongoose@4.10.2",
77 "mquery@2.3.1",
78 "debug@2.6.8",
79 "ms@2.0.0"
80 ]
81 }
82 ],
83 "licenses": []
84 },
85 "dependencyCount": 250,
86 "packageManager": "npm"
87}
Let's say you wanted to display the vulnerability name, vulnerable package and the URL to learn more about each vulnerability. Using jq as an example, you could do the following:
1curl --request POST \
2 --header "Content-Type: application/json" \
3 --header "Authorization: token <API_KEY>" \
4 'https://snyk.io/api/v1/org/orgId/project/<PROJECT_ID>/issues' \
5 | jq '"Vulnerability: \(.issues.vulnerabilities[].title) in \(.issues.vulnerabilities[].package)@\(.issues.vulnerabilities[].version) - \(.issues.vulnerabilities[].url)"'
And you’d get the following result:
1Regular Expression Denial of Service (ReDoS) in ms@0.7.1 - https://snyk.io/vuln/npm:ms:20170412
The Reporting API
In a followup blog post, we will show how you can use the enterprise reporting API to go beyond what is possible via the project issues endpoint. If you want to chart issues over time, see time to resolution and have more powerful filtering capabilities, get in touch by emailing enterprise@snyk.io to try out our reporting API.