Working with Indicators
This section demonstrates how to manage indicators in ThreatQ using the SDK, including listing, searching, creating, updating, relating, and bulk-uploading indicators.
List All Indicators
To retrieve all indicators in ThreatQ, use the tq.get() method. This method wraps authentication and performs an HTTP GET request against the ThreatQ API.
The following example calls the /api/indicators endpoint, which returns a collection of indicator objects represented as dictionaries:
print(inds.get('data')[0])
Example output:
{
"last_detected_at": null,
"hash": "51d81f46d7a042805c96e512a3e122ba",
"status_id": 1,
"created_at": "2016-10-13 14:07:56",
"type_id": 10,
"updated_at": "2016-10-13 14:07:56",
"value": "1.234.62.166",
"id": 1,
"class": "network"
}
Search for a Specific Indicator
To locate a specific indicator, pass search parameters to the tq.get() method using the params argument.
The following example searches for an indicator with the value 8.8.8.8:
print(ind.get('data'))
Example output:
[
{
"last_detected_at": null,
"hash": "9c709bf480caf30fc107cfbbc107cfbb",
"status_id": 1,
"created_at": "2016-10-14 00:02:18",
"type_id": 10,
"updated_at": "2016-12-02 09:13:14",
"value": "8.8.8.8",
"id": 535253,
"class": "network"
}
]
Create a New Indicator
Before creating an indicator, import the required SDK classes:
Create an indicator by specifying the required fields:
-
value -
type -
status
Upload the indicator to ThreatQ and capture the newly assigned indicator ID:
Add an Attribute
You can associate custom attributes with an indicator by adding key-value pairs.
Example:
This adds the attribute Disposition = Safe to the indicator.
Update an Indicator Status
To modify an existing indicator, use the tq.put() method to issue an authenticated HTTP PUT request.
The following example updates an indicator's status from Review to Active using its indicator ID:
The variable iid must contain a valid indicator ID.
Retrieve Related Objects
Indicators can be associated with other ThreatQ objects such as indicators, adversaries, events, files, and signatures.
Use the get_related_objects() method to retrieve linked objects. The method accepts an object type as its argument.
Ensure the corresponding object class has been imported before use.
Example:
rel_advs = ind.get_related_objects(Adversary)
This returns lists of related Indicator and Adversary objects.
The get_related_objects() method is also available for Event, Adversary, File, and Signature objects.
Create Relationships Between Objects
To establish a relationship between two ThreatQ objects, use the relate_object() method.
Example:
This creates a relationship between the two indicator objects.
The relate_object() method is also available for Event, Adversary, File, and Signature objects.
Bulk Upload Indicators
For large-scale indicator ingestion, use the BulkIndicator class together with the tq.bulkuploadindicators() method.
Import Required Classes
Create a Collection for Bulk Upload
Create and Configure Each Bulk Indicator
The following fields are required:
-
ind_value -
ind_type -
ind_status
bi.set_value(ind_value)
bi.set_type(ind_type)
bi.set_status(ind_status)
You can also add attributes and relationships:
bi.relate_indicator('example.com', 'FQDN')
bi.relate_adversary(adversary_id)
bi.relate_event(event_id)
After configuring the indicator, add it to the bulk upload collection:
Repeat this process for each IOC in your dataset.
Upload the Indicators
Once all indicators have been added to the collection, upload them to ThreatQ:
This submits all indicators in a single bulk operation, improving performance and reducing API overhead when ingesting large volumes of threat intelligence.
----------
Indicator Normalization and Validation
Normalization is the process of formatting indicator values into a consistent standard. This prevents duplicate indicators, ensures consistent searching/matching, and improves correlation across data sources.
Common normalization steps include:
- Converting to lowercase (domains, URLs)
- Trimming whitespace
- Removing unnecessary prefixes/suffixes
- Standardizing formats (e.g., URL structure)
Examples
| Raw Input | Normalized Value |
|---|---|
Example.COM |
example.com |
HTTP://site.com |
http://site.com |
Indicator Validation ensures the indicator is correctly formatted and valid for its type before ingestion. This prevents bad/unusable data from entering ThreatQ, reduces errors in automation/detection systems, and ensures compatibility with downstream tools.
| Type | Validation Check |
|---|---|
| IP | Valid IPv4/IPv6 format |
| Domain | Proper domain syntax |
| Hash | Correct length (MD5=32, SHA256=64) |
| URL | Proper scheme (http/https) |
Example of Normalization and Validation Workflow
value = " Example.COM "
# Normalize
normalized = value.strip().lower()
# Validate (simple example)
if "." in normalized:
payload = {
"value": normalized,
"type": "domain"
}
tq.post("/api/indicators", data=payload)