Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions services/cti_ingest/src/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ def normalize_items():
"claims": [
"Typosquatting is a recognized supply-chain technique"
]
},
{
"url": "https://www.habitsimulation.xyz/scotobot",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The key url is used here, but the TTP mapper in services/ttp_mapper/src/mapper.py (line 72) expects source_url. This discrepancy will likely cause a KeyError during the mapping phase if the item is passed directly to the mapper.

Suggested change
"url": "https://www.habitsimulation.xyz/scotobot",
"source_url": "https://www.habitsimulation.xyz/scotobot",

"title": "HABIT Human AI Behavioral Interaction Toolkit conference demo",
"content": "Conference-facing assistant promoted via QR code and external URL for live operator-agent interaction.",
"claims": [
"Conference demos that direct users to external assistant URLs increase social-engineering surface area",
"Operator-agent persuasion research should be tracked for dual-use abuse in phishing and influence operations",
"External domain solicitation from event kiosks should be reviewed with URL sandboxing and allowlist policy"
]
}
]

Expand Down
6 changes: 5 additions & 1 deletion services/cti_ingest/tests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

def test_ingest_normalization():
items = normalize_items()
assert len(items) == 5
assert len(items) == 6
assert items[0]["title"] == "Polish officials blame Russian domestic spy agency for Dec 29 cyberattacks"
assert "content_hash" in items[0]

Expand All @@ -26,6 +26,10 @@ def test_mapper_rules():
ai_mapping = mappings[1]
assert any(m["control"] == "Repo Hardening (Branch Protection)" for m in ai_mapping["mappings"])

# Check conference external URL social-engineering surface
habit_mapping = mappings[5]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the mapping by a hardcoded index (mappings[5]) is fragile. The test will break if the order of items in normalize_items() is changed or if new items are added earlier in the list. Searching by source_url is more maintainable.

Suggested change
habit_mapping = mappings[5]
habit_mapping = next(m for m in mappings if m["source_url"] == "https://www.habitsimulation.xyz/scotobot")

assert any(m["control"] == "URL Sandboxing and Domain Allowlisting" for m in habit_mapping["mappings"])

def test_pipeline_output_structure():
# This just tests the logic integration
items = normalize_items()
Expand Down
12 changes: 12 additions & 0 deletions services/ttp_mapper/src/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ def map_item(cti_item):
"trigger": "Typosquatting detected"
})

# Rule 5: Human-AI persuasion / conference external URL solicitation
if (
"human-ai persuasion" in full_text
or "external domain solicitation" in full_text
or "conference demos" in full_text
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require URL-specific signal in new phishing rule

The new rule classifies any item containing "conference demos" as T1566.002, even when there is no phishing or external-link solicitation context. In map_item, full_text is built from title/claims only, so benign CTI like conference recaps will now be mislabeled as phishing (I verified with a sample title "Conference demos for SOC tooling"). This introduces systematic false positives in ATT&CK mapping outputs; the condition should require a URL solicitation indicator (or a conjunction of terms) instead of this standalone generic phrase.

Useful? React with 👍 / 👎.

):
Comment on lines +60 to +64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current matching logic has two issues:

  1. Case Sensitivity: The keywords are lowercase, but the source data in ingest.py uses Title Case (e.g., "Conference demos"), which will fail to match in a standard string comparison.
  2. Keyword Mismatch: The keyword "human-ai persuasion" does not match the text in the ingested item, which uses "Operator-agent persuasion".

Using .lower() and aligning the keywords with the actual data will make the detection robust.

Suggested change
if (
"human-ai persuasion" in full_text
or "external domain solicitation" in full_text
or "conference demos" in full_text
):
if any(kw in full_text.lower() for kw in [
"operator-agent persuasion",
"external domain solicitation",
"conference demos"
]):

mappings.append({
"technique": "Phishing: Spearphishing Link (T1566.002)",
"control": "URL Sandboxing and Domain Allowlisting",
"trigger": "External assistant URL solicitation detected"
})

return {
"source_url": cti_item["source_url"],
"mappings": mappings
Expand Down
Loading