Github Vulnerability

Import findings from Github vulnerability scan (GraphQL Query): https://help.github.com/en/github/managing-security-vulnerabilities

Currently the parser is able to manage only RepositoryVulnerabilityAlert object. The parser has some kind of search feature which detect the data in the report.

Here is the mandatory objects and attributes:

vulnerabilityAlerts (RepositoryVulnerabilityAlert object)
    + id
    + createdAt (optional)
    + vulnerableManifestPath
    + state (optional)
    + securityVulnerability (SecurityVulnerability object)
        + severity (CRITICAL/HIGH/LOW/MODERATE)
        + package (optional)
            + name (optional)
        + advisory (SecurityAdvisory object)
            + description
                + summary
                + description
                + identifiers
                    + value
                + references (optional)
                    + url (optional)
                + cvss (optional)
                    + score (optional)
                    + vectorString (optional)
                + cwes (optional)

References:

  • https://docs.github.com/en/graphql/reference/objects#repositoryvulnerabilityalert
  • https://docs.github.com/en/graphql/reference/objects#securityvulnerability

Github v4 graphql query to fetch data, with extended information like the repository name and url, alert number.

query getVulnerabilitiesByRepoAndOwner($name: String!, $owner: String!) {
  repository(name: $name, owner: $owner) {
    vulnerabilityAlerts(first: 100, after:AFTER, states: OPEN) {
      nodes {
        id
        createdAt
        vulnerableManifestPath
        securityVulnerability {
          severity
          updatedAt
          package {
            name
            ecosystem
          }
          firstPatchedVersion {
            identifier
          }
          vulnerableVersionRange
          advisory {
            description
            summary
            identifiers {
              value
              type
            }
            references {
              url
            }
            cvss {
              vectorString
            }
          }
        }
        vulnerableManifestPath
        state
        vulnerableManifestFilename
        vulnerableRequirements
        number
        dependencyScope
        dismissComment
        dismissReason
        dismissedAt
        fixedAt
      }
      totalCount
      pageInfo {
        endCursor
        hasNextPage
        hasPreviousPage
        startCursor
      }
    }
    nameWithOwner
    url
  }
}

Another example of Python script, to have a function that queries any repository, with support for paginated responses and get all findings. Has a filter to only get OPEN dependabot alerts but this can be removed in the GraphQL query

def make_query(after_cursor=None):
    return """
query getVulnerabilitiesByRepoAndOwner($name: String!, $owner: String!) {
  repository(name: $name, owner: $owner) {
    vulnerabilityAlerts(first: 100, after:AFTER, states: OPEN) {
      nodes {
        id
        createdAt
        vulnerableManifestPath
        securityVulnerability {
          severity
          updatedAt
          package {
            name
            ecosystem
          }
          firstPatchedVersion {
            identifier
          }
          vulnerableVersionRange
          advisory {
            description
            summary
            identifiers {
              value
              type
            }
            references {
              url
            }
            cvss {
              vectorString
            }
          }
        }
        vulnerableManifestPath
        state
        vulnerableManifestFilename
        vulnerableRequirements
        number
        dependencyScope
        dismissComment
        dismissReason
        dismissedAt
        fixedAt
      }
      totalCount
      pageInfo {
        endCursor
        hasNextPage
        hasPreviousPage
        startCursor
      }
    }
    nameWithOwner
    url
  }
}
""".replace(
        "AFTER", '"{}"'.format(after_cursor) if after_cursor else "null"
    )

# accumulates all pages data into a single object
def get_dependabot_alerts_repository(repo, owner):
    keep_fetching = True
    after_cursor = None
    output_result = {"data": {"repository": {"vulnerabilityAlerts": {"nodes": []}}}}
    while keep_fetching:
        headers = {"Authorization": AUTH_TOKEN}

        request = requests.post(
            url="https://api.github.com/graphql",
            json={
                "operationName": "getVulnerabilitiesByRepoAndOwner",
                "query": make_query(after_cursor),
                "variables": {"name": repo, "owner": owner},
            },
            headers=headers,
        )

        result = request.json()
        output_result["data"]["repository"]["name"] = result["data"]["repository"][
            "name"
        ]
        output_result["data"]["repository"]["url"] = result["data"]["repository"]["url"]
        if result["data"]["repository"]["vulnerabilityAlerts"]["totalCount"] == 0:
            return None

        output_result["data"]["repository"]["vulnerabilityAlerts"]["nodes"] += result[
            "data"
        ]["repository"]["vulnerabilityAlerts"]["nodes"]

        keep_fetching = result["data"]["repository"]["vulnerabilityAlerts"]["pageInfo"][
            "hasNextPage"
        ]
        after_cursor = result["data"]["repository"]["vulnerabilityAlerts"]["pageInfo"][
            "endCursor"
        ]
    print(
        "Fetched {} alerts for repo {}/{}".format(
            result["data"]["repository"]["vulnerabilityAlerts"]["totalCount"],
            owner,
            repo,
        )
    )
    return json.dumps(output_result, indent=2)

Sample Scan Data

Sample Github Vulnerability scans can be found here.