Introduction
The Cobalt API gives you REST access to Organizations, Assets, Pentests, Findings, and Events.
API Versions
Background
When the Cobalt API was introduced in 2021, it was read-only but plans were already in place to add
write support. Initially this was envisioned as being added to v1
of the API.
A close examination of v1
of the API will reveal an odd mix of identifiers - numeric IDs, tokens,
and so on. For the sake of simplicity and consistency Cobalt decided to migrate to a common identifier
format. Due to the difficulty of maintaining full compatibility across different combinations of
identifiers, we decided to introduce v2
of the API exclusively using the new identifier format.
v1
is currently maintained but will not see any new features.
Authentication
Cobalt uses API tokens to allow access to various endpoints. You can create a new Cobalt API token from within your Cobalt profile.
Cobalt expects the API token to be included in all API requests to the server in a header that looks like the following:
Authorization: Bearer YOUR-PERSONAL-API-TOKEN
Organizations
Get All Organizations
curl -X GET "https://api.us.cobalt.io/orgs" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "or_A2bb4FE",
"name": "Acme Corp.",
"token": "e9d6da*********0e8ad"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
},
{
"resource": {
"id": "or_UX2Fg3",
"name": "Lorem Corp.",
"token": "dfd6da*********0e8ad"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/orgs?cursor=a1b2c3d4",
"prev_page": "/orgs?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of organizations, or orgs, that you belong to. Save the token
field to be used in
your X-Org-Token
header in subsequent calls in querying for assets, findings, pentests and events that belong to that
organization.
HTTP Request
GET https://api.us.cobalt.io/orgs
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/orgs?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of organizations. Example: https://api.us.cobalt.io/orgs?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the organization. Starts with or_ |
name | The name of the organization |
token | The organization token you’ll need in subsequent calls |
links.ui.url | A link to redirect an authorized user to this organization in the Cobalt web application |
Assets
Get All Assets
curl -X GET "https://api.us.cobalt.io/assets" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V1-ORGANIZATION-TOKEN"
This command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "as_rvZRC5Y",
"title": "Acme Corp. HR System",
"description": "HR system of the Acme Corp. holding sensitive employee data",
"asset_type": "web",
"logo": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/cat.jpeg?something=1",
"attachments": [
{
"token": "att_yYXZodA",
"download_url": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/rainbow.jpeg?something=1"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/assets?cursor=a1b2c3d4",
"prev_page": "/assets?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of assets that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/assets
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/assets?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of assets. Example: https://api.us.cobalt.io/assets?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the asset. Starts with as_ |
title | The title of the asset; set by user creating the asset |
description | A description of the asset; set by user creating the asset |
asset_type | An asset type, such as; api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile |
links.ui.url | A link to redirect an authorized user to this asset in the Cobalt web application |
logo | A link pointing the location of the uploaded asset logo |
attachments | A list of asset attachments. Attachment download URLs are pre-authorized and will expire after 10 minutes. |
Pentests
Get All Pentests
curl -X GET "https://api.us.cobalt.io/pentests" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V1-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "pt_rVShby8",
"title": "HR System Security Test 2022-Q4",
"objectives": "Coverage of OWASP top 10, ASVS and application logic.",
"state": "new",
"tag": "#PT5940",
"asset_id": "as_0EY8V1C",
"platform_tags": [
"rails",
"ruby",
"aws"
],
"methodology": "web",
"targets": [
"https://example.com",
"192.168.1.1"
],
"start_date": "Dec 11 2019",
"end_date": "Dec 25 2019"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/pentests?cursor=a1b2c3d4",
"prev_page": "/pentests?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all pentests that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/pentests
URL Parameters
Parameter | Default | Description |
---|---|---|
asset | N/A | If specified, returns pentests scoped to this asset id. Example: https://api.us.cobalt.io/pentests?asset=as_rvZRC5Y |
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/pentests?cursor=a1b2c3d4 |
limit | 1000 | If specified, returns only a specified amount of pentests. Example: https://api.us.cobalt.io/pentests?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest, for example, “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
platform_tags | Tech stack of the target, for example, Java, Kotlin, Ruby, or AWS. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Findings
Get All Findings
curl -X GET "https://api.us.cobalt.io/findings" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V1-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "vu_ZzZuekb",
"tag": "#PT3334_37",
"title": "XSS vulnerability",
"description": "Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts...",
"type_category": "Cross-Site Scripting (XSS)",
"labels": [
{
"name": "Your label"
}
],
"impact": 5,
"likelihood": 4,
"severity": "high",
"affected_targets": [
"https://example.com",
"192.168.1.1"
],
"proof_of_concept": "Here you can see...",
"suggested_fix": "Ensure this...",
"pentest_id": "pt_9Ig1234",
"asset_id": "as_cwrsqsL",
"log": [
{
"action": "created",
"timestamp": "2021-04-01T15:13:24.322Z"
},
{
"action": "likelihood_changed",
"value": 4,
"timestamp": "2021-04-01T15:14:05.856Z"
},
{
"action": "impact_changed",
"value": 5,
"timestamp": "2021-04-01T15:14:05.856Z"
},
{
"action": "state_changed",
"value": "need_fix",
"timestamp": "2021-04-01T15:14:06.757Z"
},
{
"action": "state_changed",
"value": "check_fix",
"timestamp": "2021-04-01T15:14:57.845Z"
}
],
"state": "check_fix"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/findings?cursor=a1b2c3d4",
"prev_page": "/findings?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all pentest findings that belong to the organization specified in the X-Org-Token
header, filterable by pentest_id
or asset_id
. The log
array presents a history of each finding and corresponding
timestamp.
Calculations
We follow the standard risk model described by OWASP, where:
Risk = Impact * Likelihood
Cobalt Risk Input Fields:
impact
: 1, 2, 3, 4, or 5likelihood
: 1, 2, 3, 4, or 5
Cobalt Risk Classification (severity
, a.k.a. criticality
):
Category | Score | Description |
---|---|---|
critical | 25 | Includes vulnerabilities that require immediate attention. |
high | 16-24 | Impacts the security of your application/platform/hardware, including supported systems. Includes high probability vulnerabilities with a high business impact. |
medium | 5-15 | Includes vulnerabilities that are: medium risk, medium impact; low risk, high impact; high risk, low impact. |
low | 2-4 | Specifies common vulnerabilities with minimal impact. |
informational | 1 | Notes vulnerabilities of minimal risk to your business. |
HTTP Request
GET https://api.us.cobalt.io/findings
GET https://api.us.cobalt.io/findings?pentest=pt_9Ig1234
GET https://api.us.cobalt.io/findings?asset=as_cwrsqsL
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/findings?cursor=a1b2c3d4 |
limit | 1000 | If specified, returns only a specified amount of findings. Example: https://api.us.cobalt.io/findings?limit=5 |
pentest | N/A | If specified, returns findings scoped to this pentest id. Example: https://api.us.cobalt.io/findings?pentest=pt_9Ig1234 |
asset | N/A | If specified, returns findings scoped to this asset id. Example: https://api.us.cobalt.io/findings?asset=as_cwrsqsL |
Response Fields
Field | Enum Types |
---|---|
log | created , impact_changed , likelihood_changed , state_changed |
severity | null , low , medium , high (aka criticality . will be null if likelihood/impact have not yet been set by the pentester) |
state | new , triaging , need_fix , wont_fix , valid_fix , check_fix , invalid , carried_over |
type_category | XSS, SQLi, … (about 30 more via the Cobalt Taxonomy) |
links.ui.url | A link to redirect an authorized user to this finding in the Cobalt web application |
State
new
: The finding has been created but not yet triaged.triaging
: The finding is being evaluated.need_fix
: The finding was deemed valid and a fix either is being developed or will be developed in the future.wont_fix
: The finding was deemed valid but immaterial or meaningless and will not be addressed.check_fix
: A fix has been applied and now is awaiting validation by the pentester.invalid
: The finding was rejected as not being a true vulnerability.carried_over
: The finding was carried over from a previous pentest.
Events
Get All Events
curl -X GET "https://api.us.cobalt.io/events" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "277603",
"action": "comment_created",
"subject": {
"id": "277603",
"type": "comment"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
},
{
"resource": {
"id": "277600",
"action": "pentest_deleted",
"subject": {
"id": "277600",
"type": "program"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
},
{
"resource": {
"id": "277567",
"action": "finding_created",
"subject": {
"id": "277567",
"type": "vulnerability"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
}
],
"pagination": {
"next_page": "/events?cursor=a1b2c3d4",
"prev_page": "/events?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all events for your account.
HTTP Request
GET https://api.us.cobalt.io/events
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/events?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of events. Example: https://api.us.cobalt.io/events?limit=5 |
Tokens
Get All Tokens
curl -X GET "https://api.us.cobalt.io/tokens" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "api_Dge3LsHMjtX8SGEk4a8nux",
"last_characters": "redacted",
"name": "Lorem ipsum",
"expire_at": null
}
}
],
"pagination": {
"next_page": null,
"prev_page": null
}
}
This endpoint retrieves a list of all tokens that belong to you.
HTTP Request
GET https://api.us.cobalt.io/tokens
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/tokens?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of tokens. Example: https://api.us.cobalt.io/tokens?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the token. Starts with api_ |
name | Name of the API token |
last_characters | This property is deprecated. Do not use it. |
expire_at | null (not currently implemented) |
Refresh Token
curl -X POST "https://api.us.cobalt.io/tokens/YOUR-TOKEN-ID/refresh" \
-H "Accept: application/vnd.cobalt.v1+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"id": "api_Dge3LsHMjtX8SGEk4a8nux",
"secret": "YOUR-NEW-PERSONAL-API-TOKEN",
"name": "Lorem ipsum",
"expire_at": null
}
You can revoke an existing token and issue a new one with the same name by making a POST request to the token refresh endpoint.
Process:
- Make a GET request to the
/tokens
endpoint and note theid
of the token you would like to refresh. - Make a POST request to the
/tokens/YOUR-TOKEN-ID/refresh
endpoint using the tokenid
obtained in the step above. - The new token will be contained in the
secret
field of the response. Note this value. Your old token will no longer work.
If you’ve forgotten your token, you can always re-authenticate in the Cobalt web app. Go to your profile, revoke the old token you’ve forgotten, and generate a new token.
HTTP Request
POST https://api.us.cobalt.io/tokens/YOUR-TOKEN-ID/refresh
Response Fields
Field | Description |
---|---|
id | A unique ID representing the new token. Starts with api_ |
secret | Your new personal API token. Keep it safe and don’t share with anyone |
name | Name of your API token |
expire_at | null (not currently implemented) |
Pagination
Pagination can be used if the number of resources for a request exceeds the value of the limit
query parameter of the
request. If the next_page
and/or prev_page
values in the response are non-null
there are additional resources.
To paginate append the next_page
or prev_page
value to the base API URL.
For example, if the next_page
value in a response is /resource?cursor=a1b2c3d4
you can send the following request
for the next page.
GET https://api.us.cobalt.io/resource?cursor=a1b2c3d4
Idempotency
The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response. For example, if a request to create an asset does not respond due to a network connection error, you can retry the request with the same idempotency key to guarantee that no more than one asset is created.
To perform an idempotent request, provide an additional Idempotency-Key: <key>
header to the request. The
header name Mutation-Check
is also supported for backwards compatibility with previous versions of the API.
An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions.
All POST
requests optionally accept idempotency keys. Idempotency keys expire after 5 minutes.
Errors
The Cobalt API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request – Your request is not good |
401 | Unauthorized – Your API token is wrong |
403 | Forbidden – You don’t have access to this resource |
404 | Not Found – The specified request could not be found |
405 | Method Not Allowed – You tried to access Cobalt data with an invalid method |
406 | Not Acceptable – You requested a format that isn’t json |
409 | Conflict – You attempted to create a resource with the same Idempotency-Key header as a recent request. |
410 | Gone – The requested endpoint has been removed from Cobalt servers |
418 | I’m a teapot |
422 | Unprocessable Entity – The content and syntax are correctly formed, but something else is off. |
429 | Too Many Requests – You’re making requests too often. |
500 | Internal Server Error – We had a problem with our server. Try again later. |
503 | Service Unavailable – We’re temporarily offline for maintenance. Please try again later. |
Subscription
If you want to receive our API updates you can subscribe to our mailing list. We will be sending you a newsletter containing changes and improvements in our API once a month. You can also unsubscribe anytime you want. Your email address won’t be shared with any other organization.