How to Use the Risks API

The Attack Surface Intelligence Risks API provides a powerful way to see your project's risks in a quick and programmatic way.

Introduction

The Risks API interface allows you to get risk information from your project's targets for which security issues have been found. Risk characteristics will be shown upon query completion.

This document will explain how to interact with the API endpoint using different programming languages.

API Endpoint Details

📘

Risks and Exposures

As of September 2023, the Attack Surface Intelligence module renamed Risk Rules to Exposures to distinguish them from Recorded Future's additional Risk Rules.

The Risks returned via the Risks API in this context should be considered synonymous with Exposures within the Recorded Future Portal.

For more information, please see the Support Article for Exposures.

Authentication

To authenticate with the API you need to create an API Key in your Attack Surface Intelligence Account Panel, instructions can be found here:

https://securitytrails.com/support/knowledge-base/account-api/#htoc-api-keys.

Request and Response Structure

Requests should be done using the ASI project's ID and the desired snapshot date (e.g. recent), authentication must be done using your SecurityTrails API key:

curl --request GET \
  --url 'https://api.securitytrails.com/v1/asi/rules/aabbccdd-1122-3344-eeff-556677889900/recent/issues' \
  --header 'apikey: YOUR_API_KEY'

Once queried, you'll receive a JSON-formatted response that will include details of all targets found to have security issues accompanied by their risks and risk details:

{
  "data": [
    {
      "id": "CVE-2021-26855",
      "name": "Exchange Server SSRF Vulnerability (CVE-2021-26855)",
      "description": "This vulnerability is part of an attack chain that could allow remote code execution on Microsoft Exchange Server. The initial attack requires the ability to make an untrusted connection to Exchange server port 443. Other portions of the chain can be triggered if an attacker already has access or can convince an administrator to open a malicious file. Be aware his CVE ID is unique from CVE-2021-26412, CVE-2021-26854, CVE-2021-26857, CVE-2021-26858, CVE-2021-27065, and CVE-2021-27078.",
      "classification": "high",
      "example_entities": {
        "domains": [
          {
            "example": "<domain>",
            "target": "https://<domain>/owa/auth/x.js"
          }
        ]
      },
      "rule_metadata": {
        "entity_counts": {
          "domains": 1,
          "ips": 0
        },
        "references": [
          "https://app.recordedfuture.com/live/sc/entity/?name=CVE-2021-26855",
          "https://gist.github.com/testanull/324546bffab2fe4916d0f9d1f03ffa09",
          "https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-26855",
          "https://proxylogon.com/#timeline",
          "https://raw.githubusercontent.com/microsoft/CSS-Exchange/main/Security/http-vuln-cve2021-26855.nse",
          "https://www.shodan.io/search?query=vuln%3ACVE-2021-26855"
        ]
      }
    }
  ],
  "meta": {
    "counts": {
      "high": 1,
      "moderate": 0,
      "informational": 0
    },
    "project_id": "<project_id>",
    "project_title": "<title>",
    "snapshot": "2022-06-17 19:41:10"
  }
}

Code Examples

Bash

PROJECT_ID="aabbccdd-1122-3344-eeff-556677889900" \
SNAPSHOT_DATE="recent" \
curl --request GET \
  --url 'https://api.securitytrails.com/v1/asi/rules/$PROJECT_ID/$SNAPSHOT_DATE/issues' \
  --header 'apikey: YOUR_API_KEY'

Python

import requests

project_id = "aabbccdd-1122-3344-eeff-556677889900"
snapshot_date = "recent"
url = "https://api.securitytrails.com/v1/asi/rules/" + project_id + "/" + snapshot_date + "/issues"

headers = {
    "APIKEY": "YOUR_API_KEY"
}

response = requests.request("GET", url, headers=headers)

print(response.text)

Java

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.securitytrails.com/v1/asi/rules/aabbccdd-1122-3344-eeff-556677889900/recent/issues")
  .get()
  .addHeader("Accept", "application/json")
  .addHeader("APIKEY", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();

PHP

<?php
$PROJECT_ID = "aabbccdd-1122-3344-eeff-556677889900";
$SNAPSHOT_DATE = "recent";  
$curl = curl_init();
curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.securitytrails.com/v1/asi/rules/".$PROJECT_ID."/".$SNAPSHOT_DATE."/issues",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "APIKEY: YOUR_API_KEY",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

?>

Golang

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
    
  	project_id := "aabbccdd-1122-3344-eeff-556677889900"
  	snapshot_date := "recent"
		url := "https://api.securitytrails.com/v1/asi/rules/" + project_id + "/" + snapshot_date + "/issues"

		req, _ := http.NewRequest("GET", url, nil)

		req.Header.Add("Accept", "application/json")
		req.Header.Add("APIKEY", "YOUR_API_KEY")

		res, _ := http.DefaultClient.Do(req)

		defer res.Body.Close()
		body, _ := ioutil.ReadAll(res.Body)

		fmt.Println(res)
		fmt.Println(string(body))

}

Ruby

require 'uri'
require 'net/http'
require 'openssl'

project_id = "aabbccdd-1122-3344-eeff-556677889900"
snapshot_date = "recent"
url = URI("https://api.securitytrails.com/v1/asi/rules/" + project_id + "/" + snapshot_date + "/issues")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Accept"] = 'application/json'
request["APIKEY"] = 'YOUR_API_KEY'

response = http.request(request)
puts response.read_body

NodeJS

const fetch = require('node-fetch');

let project_id = 'aabbccdd-1122-3344-eeff-556677889900'
let snapshot_date = 'recent'
let url = 'https://api.securitytrails.com/v1/asi/rules/' + project_id + '/' + snapshot_date + '/issues';

let options = {
  method: 'GET',
  qs: {include_ips: 'false', page: '1', scroll: 'false'},
  headers: {APIKEY: 'YOUR_API_KEY'}
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

Javascript

const options = {
  method: 'GET',
  headers: {Accept: 'application/json', APIKEY: 'YOUR_API_KEY'}
};

fetch('https://api.securitytrails.com/v1/asi/rules/aabbccdd-1122-3344-eeff-556677889900/recent/issues', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

If you need an additional proof-of-concept code in a different programming language please contact our Support Team.

Risk Issues History

Supported query params:

  • query: a string to freetext search name and description
  • rule_action: removed or added
  • classification: comma-separated string indicating high, moderate, and/or informational
  • start: timestamp, to get rule changes afterwards
  • end: timestamp, to get history up to

Add or remove the rules between each snapshot. A common workflow (e.g. that which is used in
our XSOAR integration) is to use the current issues endpoint to populate initial incidents. Then
keep track of last_fetched timestamp to periodically query the history endpoint to get newly
added rules by passing last_fetched timestamp as the start query param.

NOTE: This approach may still result in duplicates if a rule is removed and then reappears. It
will be returned as an added rule.

Each snapshot with a diff has an entry in an array under the data key. The keys added_rules
and removed_rules has an array of rules with the same schema as the above endpoint.

API Call Example:

curl --request GET \
  --url 'https://api.securitytrails.com/v1/asi/rules/history/aabbccdd-1122-3344-eeff-556677889900/activity' \
  --header 'apikey: YOUR_API_KEY'

Example response:

{
  "data": [
    {
      "added_rules": [
        {
          "classification": "moderate",
          "description": "Using 2 versions of Apache linked to 29 high risk vulnerabilities:",
          "example_entities": {
            "domains": [
              {
                "additional": "Apache 2.4.41, Apache 2.4.46",
                "example": "subdomain.mydomain.tld",
                "sort_value": 99
              }
            ],
            "ips": [
              {
                "additional": "Apache 2.4.41",
                "example": "192.168.X.Y",
                "sort_value": 99
              },
              {
                "additional": "Apache 2.4.46",
                "example": "172.31.X.Y",
                "sort_value": 99
              }
            ]
          },
          "id": "cve-Apache",
          "name": "Vulnerable Versions of Apache",
          "rule_metadata": {
            "entity_counts": {
              "domains": 2,
              "ips": 2
            },
            "examples": "CVE-2021-40438 (Apache 2.4.46), CVE-2021-44790 (Apache 2.4.46), CVE-2020-11984 (Apache 2.4.41)",
            "references": []
         }
       }
     }
   ]
 }