Produce and consume STIX 2 JSON content for cyber threat intelligence
Comprehensive data marking system for applying access control, handling restrictions, and managing classification levels on STIX objects using both object-level and granular markings.
Core functions for manipulating data markings on STIX objects.
def add_markings(obj, marking, selectors=None):
"""
Add markings to STIX objects or properties.
Parameters:
- obj: STIX object to mark
- marking: Marking definition reference or object
- selectors (list): Property selectors for granular markings
Returns:
Modified STIX object with added markings
"""
def set_markings(obj, marking, selectors=None, marking_ref=True, lang=True):
"""
Set markings on STIX objects, replacing existing markings.
Parameters:
- obj: STIX object to mark
- marking: Marking definition reference or object
- selectors (list): Property selectors for granular markings
- marking_ref (bool): Include marking definition references
- lang (bool): Include language markings
Returns:
Modified STIX object with set markings
"""
def remove_markings(obj, marking, selectors=None):
"""
Remove markings from STIX objects or properties.
Parameters:
- obj: STIX object to modify
- marking: Marking definition reference or object to remove
- selectors (list): Property selectors for granular markings
Returns:
Modified STIX object with removed markings
"""
def clear_markings(obj, selectors=None, marking_ref=True, lang=True):
"""
Clear all markings from STIX objects or properties.
Parameters:
- obj: STIX object to modify
- selectors (list): Property selectors for granular markings
- marking_ref (bool): Clear marking definition references
- lang (bool): Clear language markings
Returns:
Modified STIX object with cleared markings
"""
def get_markings(obj, selectors=None, inherited=False, descendants=False, marking_ref=True, lang=True):
"""
Get markings from STIX objects or properties.
Parameters:
- obj: STIX object to examine
- selectors (list): Property selectors for granular markings
- inherited (bool): Include inherited markings from parent objects
- descendants (bool): Include markings from descendant properties
- marking_ref (bool): Include marking definition references
- lang (bool): Include language markings
Returns:
List of marking definition references and language tags
"""
def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=False):
"""
Check if STIX object or properties are marked.
Parameters:
- obj: STIX object to check
- marking: Specific marking to check for (optional)
- selectors (list): Property selectors for granular markings
- inherited (bool): Check inherited markings
- descendants (bool): Check descendant markings
Returns:
bool: True if marked, False otherwise
"""Apply markings to entire STIX objects using the object_marking_refs property.
Usage examples:
from stix2 import add_markings, get_markings, Indicator, TLP_RED, TLP_WHITE
# Create indicator without markings
indicator = Indicator(
name="Sensitive Indicator",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[file:hashes.MD5 = 'abc123']"
)
# Add TLP:RED marking to entire object
marked_indicator = add_markings(indicator, TLP_RED)
# Check what markings are applied
markings = get_markings(marked_indicator)
print(markings) # ['marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed']
# Check if object is marked with specific marking
is_tlp_red = is_marked(marked_indicator, TLP_RED)
print(is_tlp_red) # True
# Add additional marking
double_marked = add_markings(marked_indicator, TLP_WHITE)
# Set markings (replaces existing)
white_only = set_markings(marked_indicator, TLP_WHITE)
# Remove specific marking
unmarked = remove_markings(marked_indicator, TLP_RED)
# Clear all markings
clean_indicator = clear_markings(marked_indicator)Apply markings to specific properties of STIX objects for fine-grained access control.
Usage examples:
from stix2 import add_markings, get_markings, Malware, TLP_AMBER, TLP_GREEN
# Create malware object
malware = Malware(
name="Zeus Banking Trojan",
malware_types=["trojan"],
description="Advanced banking trojan targeting financial institutions",
aliases=["Zbot", "Zeus Bot"]
)
# Mark specific properties with different classification levels
# Mark name as TLP:GREEN (low sensitivity)
malware = add_markings(malware, TLP_GREEN, ["name"])
# Mark description as TLP:AMBER (moderate sensitivity)
malware = add_markings(malware, TLP_AMBER, ["description"])
# Mark aliases as TLP:RED (high sensitivity)
malware = add_markings(malware, TLP_RED, ["aliases"])
# Get markings for specific property
name_markings = get_markings(malware, ["name"])
print(name_markings) # ['marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']
desc_markings = get_markings(malware, ["description"])
print(desc_markings) # ['marking-definition--f88d31f6-486f-44da-b317-01333bde0b82']
# Check if specific property is marked
is_name_marked = is_marked(malware, TLP_GREEN, ["name"])
print(is_name_marked) # True
# Remove marking from specific property
malware = remove_markings(malware, TLP_RED, ["aliases"])
# Clear markings from specific property
malware = clear_markings(malware, ["description"])Use advanced selectors for nested properties and list elements.
from stix2 import NetworkTraffic, add_markings, TLP_AMBER
# Create network traffic with complex structure
traffic = NetworkTraffic(
protocols=["tcp", "http"],
extensions={
"http-request-ext": {
"request_method": "GET",
"request_value": "/admin/login",
"request_version": "1.1",
"request_header": {
"User-Agent": "Malicious-Bot/1.0",
"Host": "victim.com"
}
}
}
)
# Mark nested extension properties
traffic = add_markings(traffic, TLP_AMBER, ["extensions.http-request-ext.request_value"])
traffic = add_markings(traffic, TLP_RED, ["extensions.http-request-ext.request_header.User-Agent"])
# Mark list elements by index
traffic = add_markings(traffic, TLP_GREEN, ["protocols.[0]"]) # Mark first protocol
# Mark entire nested object
traffic = add_markings(traffic, TLP_AMBER, ["extensions.http-request-ext"])
# Get markings for nested properties
ua_markings = get_markings(traffic, ["extensions.http-request-ext.request_header.User-Agent"])Built-in TLP marking definitions for standardized information sharing controls.
# Pre-defined TLP marking constants
TLP_WHITE # marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9
TLP_GREEN # marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da
TLP_AMBER # marking-definition--f88d31f6-486f-44da-b317-01333bde0b82
TLP_RED # marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5edUsage examples:
from stix2 import TLP_WHITE, TLP_GREEN, TLP_AMBER, TLP_RED, Indicator, add_markings
# Create indicators with different TLP classifications
public_indicator = Indicator(
name="Public IoC",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[domain-name:value = 'public-malware.com']",
object_marking_refs=[TLP_WHITE]
)
community_indicator = add_markings(Indicator(
name="Community IoC",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[ip-addr:value = '10.0.0.1']"
), TLP_GREEN)
limited_indicator = add_markings(Indicator(
name="Limited Distribution IoC",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[file:hashes.SHA-256 = 'abc123...']"
), TLP_AMBER)
restricted_indicator = add_markings(Indicator(
name="Highly Sensitive IoC",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[email-addr:value = 'attacker@evil.com']"
), TLP_RED)Create custom marking definitions for organization-specific classification systems.
from stix2 import MarkingDefinition, StatementMarking, add_markings
# Create custom statement marking
internal_only = MarkingDefinition(
definition_type="statement",
definition=StatementMarking(
statement="Internal Use Only - Do Not Share Outside Organization"
)
)
# Create custom TLP-like marking
custom_classification = MarkingDefinition(
definition_type="statement",
definition=StatementMarking(
statement="CONFIDENTIAL//NOFORN//PROPRIETARY"
)
)
# Apply custom markings
sensitive_report = add_markings(Report(
name="Internal Threat Assessment",
published="2021-04-23T10:30:00.000Z",
object_refs=[]
), internal_only)
classified_indicator = add_markings(Indicator(
name="Classified Indicator",
indicator_types=["malicious-activity"],
pattern_type="stix",
pattern="[ip-addr:value = '192.168.1.100']"
), custom_classification)Apply language tags for internationalization and content language identification.
from stix2 import add_markings, ThreatActor
# Create threat actor with multiple language content
threat_actor = ThreatActor(
name="APT Example",
threat_actor_types=["nation-state"],
description="Advanced persistent threat group"
)
# Add language markings for specific properties
# Mark name as English
threat_actor = add_markings(threat_actor, "en", ["name"])
# Mark description as English
threat_actor = add_markings(threat_actor, "en", ["description"])
# For objects with translated content
multilingual_actor = ThreatActor(
name="APT Example",
threat_actor_types=["nation-state"]
)
# Add language-specific granular markings
multilingual_actor = add_markings(multilingual_actor, "en", ["name"])
# Get language markings
lang_markings = get_markings(multilingual_actor, ["name"], lang=True)
print(lang_markings) # ['en']Understanding how markings are inherited and propagated through object hierarchies.
from stix2 import Bundle, add_markings, get_markings, TLP_AMBER
# Create bundle with objects
bundle = Bundle(
threat_actor,
malware,
indicator
)
# Mark entire bundle
marked_bundle = add_markings(bundle, TLP_AMBER)
# Check inherited markings on contained objects
for obj_ref in marked_bundle.objects:
inherited_markings = get_markings(obj_ref, inherited=True)
print(f"{obj_ref.type}: {inherited_markings}")
# Descendant markings - check child properties
complex_object = ObservedData(
first_observed="2021-04-23T10:30:00.000Z",
last_observed="2021-04-23T10:30:00.000Z",
number_observed=1,
objects={
"0": {
"type": "file",
"name": "malware.exe",
"hashes": {"MD5": "abc123"}
}
}
)
# Mark parent property
marked_complex = add_markings(complex_object, TLP_RED, ["objects"])
# Check descendants
desc_markings = get_markings(marked_complex, ["objects.0.name"], descendants=True)Validate and enforce marking policies on STIX objects.
from stix2.exceptions import MarkingNotFoundError, TLPMarkingDefinitionError
def validate_tlp_compliance(obj):
"""Validate TLP marking compliance."""
markings = get_markings(obj)
# Check for conflicting TLP markings
tlp_markings = [m for m in markings if 'marking-definition--' in m and
m in [TLP_WHITE, TLP_GREEN, TLP_AMBER, TLP_RED]]
if len(tlp_markings) > 1:
raise TLPMarkingDefinitionError(
"Object has multiple conflicting TLP markings",
tlp_markings
)
return tlp_markings[0] if tlp_markings else None
def enforce_minimum_classification(obj, min_classification=TLP_AMBER):
"""Ensure object meets minimum classification level."""
current_tlp = validate_tlp_compliance(obj)
tlp_hierarchy = {
TLP_WHITE: 0,
TLP_GREEN: 1,
TLP_AMBER: 2,
TLP_RED: 3
}
if not current_tlp or tlp_hierarchy.get(current_tlp, 0) < tlp_hierarchy[min_classification]:
return add_markings(obj, min_classification)
return obj
# Apply validation
try:
compliant_indicator = enforce_minimum_classification(indicator, TLP_AMBER)
tlp_level = validate_tlp_compliance(compliant_indicator)
print(f"Indicator classified as: {tlp_level}")
except TLPMarkingDefinitionError as e:
print(f"TLP validation error: {e}")Query and filter STIX objects based on their markings.
from stix2 import MemoryStore, Filter
# Create store with marked objects
store = MemoryStore([
add_markings(indicator1, TLP_WHITE),
add_markings(indicator2, TLP_GREEN),
add_markings(indicator3, TLP_AMBER),
add_markings(malware1, TLP_RED)
])
# Filter by marking level - objects marked TLP:GREEN or lower
def filter_by_tlp_level(objects, max_level=TLP_GREEN):
tlp_hierarchy = {
TLP_WHITE: 0,
TLP_GREEN: 1,
TLP_AMBER: 2,
TLP_RED: 3
}
filtered = []
for obj in objects:
markings = get_markings(obj)
tlp_markings = [m for m in markings if m in tlp_hierarchy]
if not tlp_markings: # No TLP marking = assume WHITE
filtered.append(obj)
elif any(tlp_hierarchy[m] <= tlp_hierarchy[max_level] for m in tlp_markings):
filtered.append(obj)
return filtered
# Get all objects safe for community sharing (TLP:GREEN and below)
community_safe = filter_by_tlp_level(store.query(), TLP_GREEN)
# Custom filter for unmarked objects
unmarked_objects = [obj for obj in store.query()
if not get_markings(obj)]
# Filter objects by specific marking
tlp_amber_objects = [obj for obj in store.query()
if TLP_AMBER in get_markings(obj)]Install with Tessl CLI
npx tessl i tessl/pypi-stix2