Retrieve risks details for your account through the command line by interfacing with the UpGuard API.
Before you can coordinate best practices for your organization's security plan, you need to know the full extent of external risks facing your organization but identifying these risks manually can be time-consuming and labor-intensive. With UpGuard BreachSight, you gain insight to your organization's risk profile and the cybersecurity risk factors in your publicly accessible information.
Using the UpGuard API, you can retrieve available risks within the platform, including a list of active risks detected for your account. You can always evaluate your risk profile directly within the UpGuard platform. With the UpGuard API, you can retrieve the same information from the command line and incorporate it into your security hardening process.
In this guide, you will retrieve only those risks detected for your account. You will choose from the provided options to interface with the UpGuard API through curl
, Python, or Ruby.
-
An UpGuard account with an API key that you can authenticate with. Follow our tutorial on How to authenticate with your UpGuard API key to set one up. If you don't already have an account, sign up for a free trial.
-
Familiarity with the UpGuard API. In this tutorial, you will use the query parameters to get a list of active risks for your account.
Option 1 — Using curl to retrieve risks detected for your account
You can use the curl
command to retrieve information from the internet directly within your command line terminal. You supply the options necessary to retrieve specific information against an existing URL. In this option, you will run curl
against the UpGuard API to authenticate with your UpGuard account and retrieve risk details for your account.
To follow this tutorial with curl
, you will need these additional prerequisites:
Step 1 — Retrieving all risks for your account
In this step, you will run a curl
command to retrieve your account's active risks directly within the command line.
Open a terminal window and set the API key, providing the unique alphanumeric string for your personal API key where the sample below reads your_api_key
:
$ API_KEY=your_api_key
Setting the API_KEY
variable ensures that you can call it directly in future commands without providing the unique key in every command.
Run curl
to pull information from your account:
$ curl --request GET \
--header "Authorization: $API_KEY" \
--url "https://cyber-risk.upguard.com/api/public/risks"
You set a custom header with the --header
flag, specifying that your terminal is authorized with the API key you provided earlier. Because you have already set the $API_KEY
variable with your unique key, you call the variable directly.
You then provide an endpoint within the UpGuard platform to generate a response. The /risks
path will return a list of risks detected for your account, but you can use any of the options available in our API documentation to test this feature. The base URL for all public endpoints is https://cyber-risk.upguard.com/api/public
.
You'll receive a response in the form of a comma-separated value (CSV) list with all of the vendors you currently monitor and a variety of information related to each risk, which you can then apply transformations to sort. Your output may be quite lengthy.
You'll receive an output similar to this example but with risks for your account:
{"risks":[{"id":"end_of_life_product_provisional:cpe:/a:php:php","finding":"End-of-life version of PHP detected (Provisional)","risk":"Vulnerabilities","description":"The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.","severity":"high","category":"website_sec","firstDetected":"2023-05-01T06:29:35.819047Z","hostnames":["warning.be"],"riskType":"end_of_life_product_provisional","riskSubtype":"cpe:/a:php:php"}, ... }
You can also pipe the output through jq
to pretty-print the response in a more readable format:
$ curl --request GET \
--header "Authorization: $API_KEY" \
--url "https://cyber-risk.upguard.com/api/public/risks" \
| jq
The CSV format will be parsed into a JSON array:
{
"risks": [
{
"id": "end_of_life_product_provisional:cpe:/a:php:php",
"finding": "End-of-life version of PHP detected (Provisional)",
"risk": "Vulnerabilities",
"description": "The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"severity": "high",
"category": "website_sec",
"firstDetected": "2023-05-01T06:29:35.819047Z",
"hostnames": [
"warning.be"
],
"riskType": "end_of_life_product_provisional",
"riskSubtype": "cpe:/a:php:php"
},
...
]
}
The PHP end-of-life finding is an example for one risk that might be associated with accounts. Your list of risks will differ.
Returning all risks detected for your account is a crucial step in planning your security updates. If you only want to retrieve information for a specific risk in the list, you can supply additional parameters, which you will do next.
Step 2 — Retrieving details for a specific risk
When you are coordinating your risk remediation plan, you may wish to evaluate a specific risk. The UpGuard API provides a distinct path for calling specific risk details, so you will modify the curl
command in this step to retrieve information for only one risk. This step will proceed with the end-of-life PHP vulnerability returned in the previous step.
First, note the id
string for the given risk. The risk_id
for the sample PHP risk is end_of_life_product_provisional:cpe:/a:php:php
.
You'll be sending a request to the available risks endpoint (/available_risks/v2
) and appending the specific risk ID to the URL:
$ curl --request GET \
--header "Authorization: $API_KEY" \
--url "https://cyber-risk.upguard.com/api/public/available_risks/risk?risk_id=end_of_life_product_provisional:cpe:/a:php:php"
You've revised the URL to point to the available risks metadata and, more specifically, to an individual risk ID.
If you don't use jq
to transform the data, it will return in a comma-separated format. If you pipe the output through jq
, you will receive a readable response in your terminal:
{
"id": "end_of_life_product_provisional:cpe:/a:php:php",
"group": "vulns",
"risk": "Vulnerabilities",
"generic": false,
"severity": "high",
"category": "website_sec",
"finding": "End-of-life version of PHP detected (Provisional)",
"description": "The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"remediation": "Review the product and plan the necessary updates.",
"riskType": "end_of_life_product_provisional",
"riskSubtype": "cpe:/a:php:php"
}
The remediation
attribute provides information about the type of risk and a recommendation for risk remediation, which may be beneficial as you plan your risk management process.
If you are interested in automating this GET
request as a Python or Ruby script, follow the procedure in the next section.
Option 2 — Using Python to retrieve risks detected for your account
With Python, you can work quickly and automate tasks like GET
requests. Python's precise syntax enables you to create custom scripts that can complete complex actions consistently. As you evaluate risks and vulnerabilities in your software supply chain, you may want to build systems to complete tasks quickly and efficiently in a sequential order. In this section, you will build two short scripts to retrieve risk details from UpGuard, but you can combine this script with other Python syntax to accommodate your larger needs.
To follow this tutorial with Python, you will need Python installed on your machine with a virtual environment set up.
Step 1 — Activating your Python environment
In this step, you will activate a Python virtual environment that was set up with the . You can also use an alternative virtual environment, like PyCharm or Miniconda.
You can create as many virtual programming environments as you wish, which will keep your scripts in distinct folders. This tutorial will use a directory named environments
. In your terminal, move to that directory:
$ cd environments
Activate the test environment, replacing test_env
with the name you supplied for your virtual environment:
$ source test_env/bin/activate
The name of your test environment will appear as a prefix for your terminal prompt. In this example, the name is test_env
:
(test_env) your_user@your_machine_name~/your_path
With the environment running, you can now create and run a script to retrieve risk details.
Step 2 — Retrieving all risks with Python
In this step, you will create and run a Python script to retrieve the risks detected for your account.
First, use your preferred editor to create the script file. This example uses nano
:
$ nano getRisks.py
Add the script, supplying your API key where the example reads your_api_key
:
import requests
api_key = "your_api_key"
headers = { "Authorization": api_key }
base_url = "https://cyber-risk.upguard.com/api/public"
response = requests.get(base_url + '/risks', headers=headers)
print(response.status_code)
print(response.text)
First, you import the library, which you will use to send a GET
request.
Then, you set three variables that will be used in the script. Be sure to update your_api_key
with the alphanumeric string associated with your account so that the api_key
variable can be called to authorize your request.
Note: For an added layer of security, you can set your API key in a .env
file in the root directory of your Python environment and call that file within the script using a package such as , which will ensure that your API key is not stored in the script. We have not evaluated the security of external packages like python-dotenv
, and you should consult with your security team regarding the introduction of any new tooling.
Finally, you define the GET
request with two arguments: the base_url
endpoint directing to the /risks
path and authorization using your API key as a headers
variable. The response will be stored in the response
variable. The status_code
and text
attributes of the response
object will be printed to your terminal window.
Save and close the file, then run the script:
$ python3 getRisks.py
You'll receive a CSV response similar to this output but with risks detected for your account:
200
{"risks":[{"id":"end_of_life_product_provisional:cpe:/a:php:php","finding":"End-of-life version of PHP detected (Provisional)","risk":"Vulnerabilities","description":"The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.","severity":"high","category":"website_sec","firstDetected":"2023-05-01T06:29:35.819047Z","hostnames":["warning.be"],"riskType":"end_of_life_product_provisional","riskSubtype":"cpe:/a:php:php"}, ... ]}
The first line returns the status code for the ping. This output returns 200
for a successful request.
Note: If you receive a 422
error response, review the error message to update your parameters. A 500
error response returns when a system error occurs. In that case, review the error message and try again later.
The subsequent array provides details for the risks detected for your account. The sample output provides details for only one risk but your response will likely include more.
To pretty-print the output, you'll update the Python script. Open the script file:
$ nano getRisks.py
You'll be modifying the response output to use the module:
import requests
import json
api_key = "your_api_key"
headers = { "Authorization": api_key }
base_url = "https://cyber-risk.upguard.com/api/public"
response = requests.get(base_url + '/risks', headers=headers)
formatted_string = json.dumps(response.json(), indent=4)
print(response.status_code)
print(formatted_string)
You add the json
module to your import syntax. The variables and GET
request remain as written, storing the response in a response
variable.
You then modify the output as a formatted_string
variable. You use the formatted_string
variable to prettify the JSON output in a human-readable format. The function will apply a JSON transformation to the response
output with an indentation of four spaces. You can set other formatting needs if you wish. When you print attributes of the response, you swap the text
attribute for the new formatted string
variable, which moves the response text into a JSON array.
Save and close the updated file, then run it:
$ python3 getRisks.py
You'll receive a newly formatted JSON array for the output:
200
{
"risks": [
{
"id": "end_of_life_product_provisional:cpe:/a:php:php",
"finding": "End-of-life version of PHP detected (Provisional)",
"risk": "Vulnerabilities",
"description": "The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"severity": "high",
"category": "website_sec",
"firstDetected": "2023-05-01T06:29:35.819047Z",
"hostnames": [
"warning.be"
],
"riskType": "end_of_life_product_provisional",
"riskSubtype": "cpe:/a:php:php"
},
...
]
}
To send the output to a new file, append the command with an output redirection to a file using the >
operator:
$ python3 getRisks.py > getRisks.txt
With this redirection, the output will be saved to a file named getRisks.txt
(but you can supply whatever file name you like) instead of displaying in your terminal. You can run cat
to display the new file in the terminal in order to confirm the redirection, or you can access the file in your machine's document structure as needed.
Risk detection for your account follows the scanning protocols that UpGuard has in place, including port scanning and risk data collection, so you may opt to run a risk detection script periodically. Assessing risks detected on a regular cadence will ensure that you can prioritize according to your remediation process.
In this step, you retrieved information for all risks detected for your account. Next, you'll retrieve details for one specific risk by its risk identification label.
Step 3 — Retrieving details for a single risk with Python
If you know the risk id for a particular risk, you can retrieve the details quickly with a call to the UpGuard API. In this step, you'll retrieve information for the same sample risk that has been used throughout this guide: the PHP end-of-life provisional risk.
You'll create a new scripting file. Provide any name that you will remember; this example uses getOneRisk.py
:
$ nano getOneRisk.py
You'll use the same script as in the previous step, updating it to include a parameter query and a different URL endpoint:
import requests
api_key = "your_api_key"
headers = { "Authorization": api_key }
params = {"risk_id": "end_of_life_product_provisional:cpe:/a:php:php" }
base_url = "https://cyber-risk.upguard.com/api/public"
response = requests.get(base_url + '/available_risks/risk', headers=headers, params=params)
print(response.status_code)
print(response.text)
Be sure to supply your unique alphanumeric API key.
You add a new params
variable with the risk_id
query. In this example, you provide the string for the PHP end-of-life risk, but you can optionally supply a different risk_id
string. You also update the GET
request to call the /available_risks/risk
path and include the params
variable in the call.
Save and close the file, then run the script. You'll receive an output with the status_code
followed by the risk details:
200
{"id":"end_of_life_product_provisional:cpe:/a:php:php","group":"vulns","risk":"Vulnerabilities","generic":false,"severity":"high","category":"website_sec","finding":"End-of-life version of PHP detected (Provisional)","description":"The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.","remediation":"Review the product and plan the necessary updates.","riskType":"end_of_life_product_provisional","riskSubtype":"cpe:/a:php:php"}
You can modify the file with the same adjustments as in the previous step in order to prettify the JSON output. You can also append the command with the redirection operator to save the output to a named file.
If you are interested in automating this GET
request as a Ruby script, follow the procedure in the next section.
Option 3 — Using Ruby to retrieve risks detected for your account
You can use Ruby to process data retrieved from the web. Like Python, Ruby can be helpful in automating tasks with a logical script. As you evaluate risks and vulnerabilities in your software supply chain, you may want to build systems to complete tasks quickly and efficiently in a sequential order. In this section, you will build two short scripts to retrieve risk details from UpGuard, but you can combine this script with other Ruby syntax to accommodate your larger needs.
To follow this tutorial with Ruby, you will need these additional prerequisites:
Step 1 — Preparing your Ruby environment
Before writing scripts in Ruby, you should ensure that you have the necessary prerequisites. If you have confirmed that you have Ruby and the required modules on your machine, you can proceed to Step 2. Otherwise, follow the procedure in this section.
To begin, check if you have Ruby installed on your machine:
$ ruby -v
If Ruby is installed, you will receive an output with the version number, such as:
ruby 3.2.2
If Ruby is not installed, you will need to install it now.
For macOS, you can install Ruby with Homebrew:
$ brew install ruby
Note: macOS comes with a version of Ruby already installed. However, you will not be able to change anything with the pre-installed version, so you will not be able to install the required gems for this tutorial unless you install a separate version of Ruby. When you run brew install ruby
, follow the recommended steps after installation to ensure that you can modify the new version.
For Linux or WSL, you can install Ruby with your preferred package manager. For example, you could use the to install Ruby with the following command:
$ sudo apt install ruby-full
Confirm that you have installed Ruby:
$ ruby -v
You will now receive an output with the version number, such as:
ruby 3.2.2
Next, you will install the httparty
and json
gems. Gems package third-party Ruby libraries that empower you to create complex Ruby scripts.
Note: For macOS, ensure that you have installed a separate version of Ruby that you can modify. Otherwise you may receive a permissions error that you cannot write to the Ruby directory.
You can use the Ruby Gem installer for both httparty
and json
:
$ gem install httparty
$ gem install json
For each gem, you will receive a response in the terminal that the gem is being fetched and installed. To confirm the installations, you can the the command gem list
to receive an output of all the Ruby gems that are installed locally on your machine.
Note: The pp
gem comes packaged with Ruby. If you installed a fresh version of Ruby, you can run gem list
to confirm that pp
is available. Otherwise, run gem install pp
to ensure it is available.
Now that you have Ruby and the necessary gems installed on your machine, you can now create the script to retrieve risk details.
Step 2 — Retrieving all risks with Ruby
In this step, you will create and run a Ruby script to retrieve the risks detected for your account.
First, use your preferred editor to create the script file. This example uses nano
:
$ nano getRisks.rb
Add the script, supplying your API key where the example reads your_api_key
:
require 'httparty'
require 'json'
require 'pp'
$api_key = "your_api_key"
$base_url = "https://cyber-risk.upguard.com/api/public"
response = HTTParty.get(
"#{$base_url}/risks",
:headers => { "Authorization" => $api_key }
)
response = JSON.parse(response.body)
pp response
First, you define the three gems that will be used in this script: - to run the GET
request. - to parse the response output. - to pretty-print the output in a readable format.
Note: You can optionally omit the pp
gem and provide a standard puts
or print
method to return the response output. If you make this adjustment, the output will return in a CSV format rather than a readable JSON array.
You then set two variables: one for your unique alphanumeric API key and one for the public API endpoint.
Next, you define the GET
request to point to the /risks
path on the endpoint, calling your API key to authorize the request.
Finally, you parse the response output and pretty-print it to your terminal.
Save and close the file, then run it:
$ ruby getRisks.rb
You'll receive a response similar to following (truncated for length):
{"risks"=>
{"id"=>"end_of_life_product_provisional:cpe:/a:php:php",
"finding"=>"End-of-life version of PHP detected (Provisional)",
"risk"=>"Vulnerabilities",
"description"=>
"The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"severity"=>"high",
"category"=>"website_sec",
"firstDetected"=>"2023-05-01T06:29:35.819047Z",
"hostnames"=>["warning.be"],
"riskType"=>"end_of_life_product_provisional",
"riskSubtype"=>"cpe:/a:php:php"},
}
...
}
Note: If you modify the line from pp
to a puts
or print
method, your output will be in a CSV format.
Now that you can retrieve all risks for your account, you'll create another risk to return details for one specific risk.
Step 3 — Retrieving details for a single risk with Ruby
When you know the risk id for a particular risk, you can retrieve the details quickly with a call to the UpGuard API. In this step, you'll retrieve information for the same sample risk that has been used throughout this guide: the PHP end-of-life provisional risk.
You'll create a new scripting file. Provide any name that you will remember:
$ nano getOneRisk.rb
You'll use the same script as in the previous step, updating it to include a parameter query and a different URL endpoint:
require 'httparty'
require 'json'
require 'pp'
$api_key = "your_api_key"
$base_url = "https://cyber-risk.upguard.com/api/public"
$param = ("?risk_id=end_of_life_product_provisional:cpe:/a:php:php")response = HTTParty.get(
"#{$base_url}/available_risks/risk" + $param,
:headers => { "Authorization" => $api_key }
)response = JSON.parse(response.body)
pp response
You set the parameter and then call it in the GET
request.
Save and close the file, then run it:
$ ruby getOneRisk.rb
You'll receive an output for the specified risk:
{"id"=>"end_of_life_product_provisional:cpe:/a:php:php",
"group"=>"vulns",
"risk"=>"Vulnerabilities",
"generic"=>false,
"severity"=>"high",
"category"=>"website_sec",
"finding"=>"End-of-life version of PHP detected (Provisional)",
"description"=>
"The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"remediation"=>"Review the product and plan the necessary updates.",
"riskType"=>"end_of_life_product_provisional",
"riskSubtype"=>"cpe:/a:php:php"}
Note: The current Ruby script will output the data in a readable JSON array. You can optionally replace the pp
method with a puts
or print
method, which will return the output in a CSV format.
You can redirect the output while running the script to save it to a new file, or you can update the script to save the response to a file.
The remediation
attribute provides information about the type of risk and a recommendation for risk remediation, which may be beneficial as you plan your risk management process. In the next section, you will review the various attributes for details.
Evaluating the risk details
For each individual risk, the response details will include an array containing some of available attribute responses. You can use these details to coordinate your risk remediation plan and otherwise provision security updates to your supply chain. This section will explain the aspects of the response schema, using the PHP end-of-life risk as the example risk.
The response schema may include any of the following 11 attributes when retrieving all active risks for your account:
-
category
returns a string containing the risk category from UpGuard's risk categories. -
description
provides a long description of the risk. -
finding
provides a short description of the finding. -
firstDetected
returns a string with the date and time that the risk was first detected for your account. -
hostnames
returns an array with hostnames where the risk was detected. -
id
provides the specific risk identifier. -
risk
returns a short description of the risk. -
riskSubtype
returns a subtype of the risk when verified, but will be empty if the risk has no subtype. -
riskType
specifies the type of risk from the fullriskSubtype
string. -
risk_waivers
supplies an array of risk waivers applicable to this risk (if any) and has its own set of attributes relevant to the risk waiver. -
severity
lists the severity of the risk frompass
,info
,low
,medium
,high
, orcritical
.
For example, the following output indicates the PHP end-of-life risk when it appears in a list of risks:
{
"risks": [
{
"id": "end_of_life_product_provisional:cpe:/a:php:php",
"finding": "End-of-life version of PHP detected (Provisional)",
"risk": "Vulnerabilities",
"description": "The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"severity": "high",
"category": "website_sec",
"firstDetected": "2023-05-01T06:29:35.819047Z",
"hostnames": [
"warning.be"
],
"riskType": "end_of_life_product_provisional",
"riskSubtype": "cpe:/a:php:php"
},
...
]
}
This particular risk is a high severity vulnerability in the Website Security category and impacts the sample hostname warning.be
. The resulting recommendation would be to assess and update the PHP version associated with that domain.
When retrieving only one specific risk, the response schema may include these additional attributes:
-
generic
returns a boolean response indicating whether the risk is a generic risk. -
group
returns a string with the risk grouping. -
remediation
returns a recommendation for how to mitigate the risk vulnerabilities.
Retrieving details for only the specific sample risk will return an output like the following:
{
"id": "end_of_life_product_provisional:cpe:/a:php:php",
"group": "vulns",
"risk": "Vulnerabilities",
"generic": false,
"severity": "high",
"category": "website_sec",
"finding": "End-of-life version of PHP detected (Provisional)",
"description": "The detected version of PHP is end of life. The product will likely not receive security updates from the vendor moving forward.",
"remediation": "Review the product and plan the necessary updates.",
"riskType": "end_of_life_product_provisional",
"riskSubtype": "cpe:/a:php:php"
}
This response includes more information on the risk type, indicates that the risk is unique rather than generic, and provides a recommendation for risk mitigation.
Retrieving details for specific risks can support your risk remediation planning and organizational processes.
Further reading
To learn more about risk management with UpGuard, read these articles next: