What happened
In IntelOwl, an Investigation associates with root jobs via Investigation.jobs. When subsequent pivots or playbook actions are executed within the investigation, the resulting child jobs are organized hierarchically as descendants in the job tree (django-treebeard MP_Node).
Currently, Investigation.tags and Investigation.tlp in api_app/investigations_manager/models.py only query self.jobs:
@property
def tags(self) -> List[str]:
return list(set(self.jobs.values_list("tags__label", flat=True)))
@property
def tlp(self) -> TLP:
return (
max(TLP[tlp_string] for tlp_string in self.jobs.values_list("tlp", flat=True))
if self.jobs.exists()
else TLP.CLEAR.value
)
This causes several concrete bugs:
- Omission of Descendant Job TLPs (Security / Data Classification Leak): If a root job is submitted with
TLP:CLEAR and a subsequent pivot job analyzes an observable marked with TLP:AMBER or TLP:RED, investigation.tlp ignores all descendant jobs and evaluates to TLP.CLEAR. This surfaces an inaccurate classification in summarize_investigation (api_app/chatbot_manager/agent/tools/summarize_investigation.py:57), REST serializers (InvestigationSerializer), and the TLP filter (InvestigationFilter.filter_for_tlp).
- Omission of Descendant Job Tags: Tags attached to pivoted or child jobs are excluded from
investigation.tags, breaking tag filtering (filter_for_tags) and chatbot investigation summaries.
- Inconsistent Return Type on Empty Investigations:
Investigation.tlp declares -> TLP:. When self.jobs.exists() is False, it returns TLP.CLEAR.value (a str), whereas when jobs exist, it returns a TLP enum instance (TLP.CLEAR). Callers relying on enum properties (e.g., investigation.tlp.value) raise AttributeError: 'str' object has no attribute 'value' when an investigation has no jobs.
- Defects in
TLP Enum Comparison (api_app/choices.py):
__compare raises TypeError(f"Can sum {self.__class__.__name__} with {type(other)}") instead of "Cannot compare".
TLP only defines __lt__ and __gt__, omitting __le__ and __ge__ and failing when compared against raw valid TLP string values.
Environment
- OS: Linux / macOS
- IntelOwl version: develop (commit 862df0a)
What did you expect to happen
Investigation.tlp should evaluate the maximum TLP across all jobs in the investigation tree (both root jobs and descendant nodes), returning TLP.CLEAR as a consistent TLP instance when empty.
Investigation.tags should aggregate distinct tags across both root and descendant jobs in the investigation tree.
TLP comparisons should support complete comparison operators (<=, >=, <, >) and cleanly compare with valid string representations.
How to reproduce your issue
from api_app.investigations_manager.models import Investigation
from api_app.models import Job, Analyzable
from api_app.choices import Classification
# 1. Type inconsistency on empty investigation
empty_inv = Investigation.objects.create(name="Empty", owner=user)
print(type(empty_inv.tlp)) # <class 'str'> instead of <enum 'TLP'>
# 2. Descendant job TLP omission
analyzable = Analyzable.objects.create(name="target.com", classification=Classification.DOMAIN)
root_job = Job.objects.create(analyzable=analyzable, user=user, tlp="CLEAR")
inv = Investigation.objects.create(name="Pivot Test", owner=user)
inv.jobs.add(root_job)
# Add a child job with higher TLP
child_job = root_job.add_child(analyzable=analyzable, user=user, tlp="RED")
inv.refresh_from_db()
print(inv.tlp) # CLEAR instead of RED
Error messages and logs
When accessing .value or enum attributes on an empty investigation:
AttributeError: 'str' object has no attribute 'value'
What happened
In IntelOwl, an
Investigationassociates with root jobs viaInvestigation.jobs. When subsequent pivots or playbook actions are executed within the investigation, the resulting child jobs are organized hierarchically as descendants in the job tree (django-treebeardMP_Node).Currently,
Investigation.tagsandInvestigation.tlpinapi_app/investigations_manager/models.pyonly queryself.jobs:This causes several concrete bugs:
TLP:CLEARand a subsequent pivot job analyzes an observable marked withTLP:AMBERorTLP:RED,investigation.tlpignores all descendant jobs and evaluates toTLP.CLEAR. This surfaces an inaccurate classification insummarize_investigation(api_app/chatbot_manager/agent/tools/summarize_investigation.py:57), REST serializers (InvestigationSerializer), and the TLP filter (InvestigationFilter.filter_for_tlp).investigation.tags, breaking tag filtering (filter_for_tags) and chatbot investigation summaries.Investigation.tlpdeclares-> TLP:. Whenself.jobs.exists()isFalse, it returnsTLP.CLEAR.value(astr), whereas when jobs exist, it returns aTLPenum instance (TLP.CLEAR). Callers relying on enum properties (e.g.,investigation.tlp.value) raiseAttributeError: 'str' object has no attribute 'value'when an investigation has no jobs.TLPEnum Comparison (api_app/choices.py):__compareraisesTypeError(f"Can sum {self.__class__.__name__} with {type(other)}")instead of"Cannot compare".TLPonly defines__lt__and__gt__, omitting__le__and__ge__and failing when compared against raw valid TLP string values.Environment
What did you expect to happen
Investigation.tlpshould evaluate the maximum TLP across all jobs in the investigation tree (both root jobs and descendant nodes), returningTLP.CLEARas a consistentTLPinstance when empty.Investigation.tagsshould aggregate distinct tags across both root and descendant jobs in the investigation tree.TLPcomparisons should support complete comparison operators (<=,>=,<,>) and cleanly compare with valid string representations.How to reproduce your issue
Error messages and logs
When accessing
.valueor enum attributes on an empty investigation: