npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
Use this skill when:
- Producing weekly, monthly, or quarterly threat intelligence summaries for security leadership
- Creating a rapid intelligence assessment in response to a breaking threat (e.g., new zero-day, active ransomware campaign)
- Generating sector-specific threat briefings for executive decision-making on security investments
Do not use this skill for raw IOC distribution — use TIP/MISP for automated IOC sharing and reserve report generation for analyzed, finished intelligence.
Prerequisites
- Completed analysis from collection and processing phase (PIRs partially or fully answered)
- Audience profile: technical level, decision-making authority, information classification clearance
- TLP classification decision for the product
- Organization-specific reporting template aligned to audience expectations
Workflow
Step 1: Determine Report Type and Audience
Select the appropriate intelligence product type:
Strategic Intelligence Report: For C-suite, board, risk committee
- Content: Threat landscape trends, adversary intent vs. capability, risk to business objectives
- Format: 1–3 pages, minimal jargon, business impact language, recommended decisions
- Frequency: Monthly/Quarterly
Operational Intelligence Report: For CISO, security directors, IR leads
- Content: Active campaigns, adversary TTPs, defensive recommendations, sector peer incidents
- Format: 3–8 pages, moderate technical detail, mitigation priority list
- Frequency: Weekly
Tactical Intelligence Bulletin: For SOC analysts, threat hunters, vulnerability management
- Content: Specific IOCs, YARA rules, Sigma detections, CVEs, patching guidance
- Format: Structured tables, code blocks, 1–2 pages
- Frequency: Daily or as-needed
Flash Report: Urgent notification for imminent or active threats
- Content: What is happening, immediate risk, what to do right now
- Format: 1 page maximum, distributed within 2 hours of threat identification
- Frequency: As-needed (zero-day, active campaign targeting sector)
Step 2: Structure Report Using Intelligence Standards
Apply intelligence writing standards from government and professional practice:
Headline/Key Judgment: Lead with the most important finding in plain language.
- Bad: "This report examines threat actor TTPs associated with Cl0p ransomware"
- Good: "Cl0p ransomware group is actively exploiting CVE-2024-20353 in Cisco ASA devices to gain initial access; organizations using unpatched ASA appliances face imminent ransomware risk"
Confidence Qualifiers (use language from DNI ICD 203):
- High confidence: "assess with high confidence" — strong evidence, few assumptions
- Medium confidence: "assess" — credible sources but analytical assumptions required
- Low confidence: "suggests" — limited sources, significant uncertainty
Evidence Attribution: Cite sources using reference numbers [1], [2]; maintain source anonymization in TLP:AMBER/RED products.
Step 3: Write Report Body
Use structured format:
Executive Summary (3–5 bullet points): Key findings, immediate business risk, top recommended action
Threat Overview: Who is the adversary? What is their objective? Why does this matter to us?
Technical Analysis: TTPs with ATT&CK technique IDs, IOCs, observed campaign behavior
Impact Assessment: Potential operational, financial, reputational impact if attack succeeds
Recommended Actions: Prioritized, time-bound defensive measures with owner assignment
Appendices: Full IOC lists, YARA rules, Sigma detections, raw source references
Step 4: Apply TLP and Distribution Controls
Select TLP based on source sensitivity and sharing agreements:
- TLP:RED: Named recipients only; cannot be shared outside briefing room
- TLP:AMBER+STRICT: Organization only; no sharing with subsidiaries or partners
- TLP:AMBER: Organization and trusted partners with need-to-know
- TLP:GREEN: Community-wide sharing (ISAC members, sector peers)
- TLP:WHITE/CLEAR: Public distribution; no restrictions
Include TLP watermark on every page header and footer.
Step 5: Review and Quality Control
Before dissemination, apply these checks:
- Accuracy: Are all facts sourced and cited? No unsubstantiated claims.
- Clarity: Can the target audience understand this without additional context?
- Actionability: Does every report section drive a decision or action?
- Classification: Is TLP correctly applied? No source identification in AMBER/RED products?
- Timeliness: Is this intelligence still current? Events older than 48 hours require freshness assessment.
Key Concepts
| Term | Definition |
|---|---|
| Finished Intelligence | Analyzed, contextualized intelligence product ready for consumption by decision-makers; distinct from raw collected data |
| Key Judgment | Primary analytical conclusion of a report; clearly stated in opening paragraph |
| TLP | Traffic Light Protocol — FIRST-standard classification system for controlling intelligence sharing scope |
| ICD 203 | Intelligence Community Directive 203 — US government standard for analytic standards including confidence language |
| Flash Report | Urgent, time-sensitive intelligence notification for imminent threats; prioritizes speed over depth |
| Intelligence Gap | Area where collection is insufficient to answer a PIR; should be explicitly documented in reports |
Tools & Systems
- ThreatConnect Reports: Built-in report templates with ATT&CK mapping, IOC tables, and stakeholder distribution controls
- Recorded Future: Pre-built intelligence report templates with automated sourcing from proprietary datasets
- OpenCTI Reports: STIX-based report objects with linked entities for structured finished intelligence
- Microsoft Word/Confluence: Common report delivery formats; use organization-approved templates with TLP headers
Common Pitfalls
- Writing for analysts instead of the audience: Technical detail appropriate for SOC analysts overwhelms executives. Maintain strict audience segmentation.
- Omitting confidence levels: Statements presented without confidence qualifiers appear as established facts when they may be low-confidence assessments.
- Intelligence without recommendations: Reports that describe threats without prescribing actions leave stakeholders without direction.
- Stale intelligence: Publishing a report on a threat campaign that was resolved 2 weeks ago creates alarm without utility. Include freshness dating on all claims.
- Over-classification: Applying TLP:RED to information that could be TLP:GREEN impedes community sharing and limits defensive value across the sector.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.8 KB
API Reference: Threat Intelligence Report Generator Agent
Dependencies
| Library | Version | Purpose |
|---|---|---|
| jinja2 | >=3.1 | Template rendering for report generation |
CLI Usage
python scripts/agent.py \
--type operational \
--data /cases/intel_data.json \
--output-dir /cases/reports/ \
--output report_meta.jsonReport Types
| Type | Audience | Length | Frequency |
|---|---|---|---|
| strategic | C-suite, board, risk committee | 1-3 pages | Monthly/Quarterly |
| operational | CISO, security directors, IR leads | 3-8 pages | Weekly |
| tactical | SOC analysts, threat hunters | 1-2 pages | Daily/as-needed |
| flash | All security staff | 1 page max | Urgent/as-needed |
Functions
confidence_label(level) -> str
Maps confidence levels to ICD 203 language: "high" -> "We assess with high confidence", "medium" -> "We assess", "low" -> "Evidence suggests".
render_report(report_type, data) -> str
Renders a Jinja2 template with the provided data dict. Sets defaults for date, org, tlp.
validate_report_data(report_type, data) -> list
Validates required fields per report type. Returns list of error strings.
quality_check(rendered) -> list
Checks rendered report for: minimum length, TLP marker presence, unqualified confidence statements.
generate_report(report_type, data_path, output_dir) -> dict
Full pipeline: load JSON data, validate, render template, run quality checks, save Markdown output.
TLP Levels
| Level | Sharing Scope |
|---|---|
| RED | Named recipients only |
| AMBER+STRICT | Organization only |
| AMBER | Organization and trusted partners |
| GREEN | Community-wide (ISAC, sector peers) |
| CLEAR | Public distribution |
Input Data Schema (Operational Example)
{
"title": "APT29 Campaign Targeting Financial Sector",
"tlp": "AMBER",
"org": "Security Operations Center",
"executive_summary": ["APT29 actively targeting financial institutions..."],
"adversary": {
"name": "APT29 / Cozy Bear",
"motivation": "Espionage",
"sophistication": "Advanced",
"target_sectors": ["Financial", "Government"]
},
"ttps": [{"tactic": "Initial Access", "technique_id": "T1566.001", "name": "Spearphishing", "observed": "2025-03-01"}],
"key_judgments": [{"confidence": "high", "statement": "APT29 will continue targeting...", "evidence": "..."}],
"recommendations": [{"priority": "Critical", "description": "...", "owner": "SOC", "timeframe": "24h", "details": "..."}],
"iocs": [{"type": "domain", "value": "evil[.]com", "context": "C2", "confidence": "high"}]
}Output
The agent produces two files:
{type}_report_{date}.md- Rendered Markdown report with TLP headersreport_meta.json- Metadata including validation errors and quality issues
Scripts 1
agent.py8.7 KB
#!/usr/bin/env python3
"""Threat intelligence report generation agent using jinja2 for template-based reporting."""
import argparse
import json
import logging
import os
import sys
from datetime import datetime
from typing import List
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
try:
from jinja2 import Environment, BaseLoader
except ImportError:
sys.exit("jinja2 required: pip install jinja2")
TLP_LEVELS = {
"RED": "Named recipients only; do not share outside the briefing room",
"AMBER+STRICT": "Organization only; no sharing with partners or subsidiaries",
"AMBER": "Organization and trusted partners with need-to-know",
"GREEN": "Community-wide sharing (ISAC members, sector peers)",
"CLEAR": "Public distribution; no restrictions",
}
CONFIDENCE_MAP = {
"high": "We assess with high confidence",
"medium": "We assess",
"low": "Evidence suggests",
}
REPORT_TEMPLATES = {
"strategic": """
# {{ title }}
**TLP:{{ tlp }}** | {{ date }} | {{ org }}
## Executive Summary
{% for point in executive_summary %}
- {{ point }}
{% endfor %}
## Threat Landscape Overview
{{ threat_overview }}
## Business Impact Assessment
{{ impact_assessment }}
## Key Judgments
{% for judgment in key_judgments %}
{{ loop.index }}. {{ confidence_label(judgment.confidence) }} that {{ judgment.statement }}
- Evidence: {{ judgment.evidence }}
{% endfor %}
## Recommended Strategic Actions
{% for action in recommendations %}
- **{{ action.priority }}** ({{ action.timeframe }}): {{ action.description }}
{% endfor %}
## Intelligence Gaps
{% for gap in intelligence_gaps %}
- {{ gap }}
{% endfor %}
---
Classification: TLP:{{ tlp }} - {{ tlp_description }}
""",
"operational": """
# {{ title }}
**TLP:{{ tlp }}** | {{ date }} | {{ org }}
## Executive Summary
{% for point in executive_summary %}
- {{ point }}
{% endfor %}
## Active Campaign Analysis
### Adversary Profile
- **Name**: {{ adversary.name }}
- **Motivation**: {{ adversary.motivation }}
- **Sophistication**: {{ adversary.sophistication }}
- **Target Sectors**: {{ adversary.target_sectors | join(', ') }}
### TTPs (MITRE ATT&CK)
| Tactic | Technique ID | Technique Name | Observed |
|--------|-------------|----------------|----------|
{% for ttp in ttps %}
| {{ ttp.tactic }} | {{ ttp.technique_id }} | {{ ttp.name }} | {{ ttp.observed }} |
{% endfor %}
## Key Judgments
{% for judgment in key_judgments %}
{{ loop.index }}. {{ confidence_label(judgment.confidence) }} that {{ judgment.statement }}
{% endfor %}
## Defensive Recommendations
{% for action in recommendations %}
### {{ action.priority }}: {{ action.description }}
- **Owner**: {{ action.owner }}
- **Timeframe**: {{ action.timeframe }}
- **Details**: {{ action.details }}
{% endfor %}
## IOC Summary
| Type | Value | Context | Confidence |
|------|-------|---------|------------|
{% for ioc in iocs %}
| {{ ioc.type }} | {{ ioc.value }} | {{ ioc.context }} | {{ ioc.confidence }} |
{% endfor %}
---
Classification: TLP:{{ tlp }} - {{ tlp_description }}
""",
"tactical": """
# {{ title }}
**TLP:{{ tlp }}** | {{ date }} | {{ org }}
## Summary
{{ summary }}
## Indicators of Compromise
| Type | Value | Context | Confidence |
|------|-------|---------|------------|
{% for ioc in iocs %}
| {{ ioc.type }} | `{{ ioc.value }}` | {{ ioc.context }} | {{ ioc.confidence }} |
{% endfor %}
## Detection Rules
{% for rule in detection_rules %}
### {{ rule.name }} ({{ rule.format }})
```
{{ rule.content }}
```
{% endfor %}
## MITRE ATT&CK Mapping
{% for ttp in ttps %}
- **{{ ttp.technique_id }}** - {{ ttp.name }}: {{ ttp.description }}
{% endfor %}
## Patching Guidance
{% for patch in patches %}
- **{{ patch.cve }}**: {{ patch.description }} ({{ patch.severity }})
{% endfor %}
---
Classification: TLP:{{ tlp }} - {{ tlp_description }}
""",
"flash": """
# FLASH: {{ title }}
**TLP:{{ tlp }}** | {{ date }} | IMMEDIATE ACTION REQUIRED
## What Is Happening
{{ what_is_happening }}
## Immediate Risk
{{ immediate_risk }}
## What To Do Right Now
{% for action in immediate_actions %}
{{ loop.index }}. {{ action }}
{% endfor %}
## Indicators of Compromise
{% for ioc in iocs %}
- {{ ioc.type }}: `{{ ioc.value }}`
{% endfor %}
## Additional Context
{{ context }}
---
Classification: TLP:{{ tlp }} - {{ tlp_description }}
Disseminated: {{ date }}
""",
}
def confidence_label(level: str) -> str:
"""Map confidence level to ICD 203 language."""
return CONFIDENCE_MAP.get(level.lower(), "Evidence suggests")
def render_report(report_type: str, data: dict) -> str:
"""Render a threat intelligence report from template and data."""
template_str = REPORT_TEMPLATES.get(report_type)
if not template_str:
raise ValueError(f"Unknown report type: {report_type}. Available: {list(REPORT_TEMPLATES.keys())}")
data.setdefault("date", datetime.utcnow().strftime("%Y-%m-%d"))
data.setdefault("org", "Security Operations")
data.setdefault("tlp", "AMBER")
data["tlp_description"] = TLP_LEVELS.get(data["tlp"], "")
env = Environment(loader=BaseLoader())
env.globals["confidence_label"] = confidence_label
template = env.from_string(template_str)
return template.render(**data)
def validate_report_data(report_type: str, data: dict) -> List[str]:
"""Validate that required fields are present for the report type."""
errors = []
required_all = ["title", "tlp"]
for field in required_all:
if field not in data:
errors.append(f"Missing required field: {field}")
if data.get("tlp") and data["tlp"] not in TLP_LEVELS:
errors.append(f"Invalid TLP level: {data['tlp']}. Valid: {list(TLP_LEVELS.keys())}")
type_required = {
"strategic": ["executive_summary", "threat_overview", "key_judgments", "recommendations"],
"operational": ["executive_summary", "adversary", "ttps", "recommendations"],
"tactical": ["summary", "iocs"],
"flash": ["what_is_happening", "immediate_risk", "immediate_actions"],
}
for field in type_required.get(report_type, []):
if field not in data:
errors.append(f"Missing field for {report_type} report: {field}")
return errors
def quality_check(rendered: str) -> List[str]:
"""Run quality checks on rendered report."""
issues = []
if len(rendered) < 200:
issues.append("Report is very short; may lack sufficient detail")
if "TLP:" not in rendered:
issues.append("Missing TLP classification marker")
unqualified = 0
for keyword in ["will", "is certain", "definitely", "undoubtedly"]:
if keyword in rendered.lower():
unqualified += 1
if unqualified > 0:
issues.append(f"Found {unqualified} statements that may need confidence qualifiers")
return issues
def generate_report(report_type: str, data_path: str, output_dir: str) -> dict:
"""Load data, validate, render, and save the report."""
with open(data_path, "r") as f:
data = json.load(f)
validation_errors = validate_report_data(report_type, data)
if validation_errors:
logger.warning("Validation issues: %s", validation_errors)
rendered = render_report(report_type, data)
quality_issues = quality_check(rendered)
if quality_issues:
logger.warning("Quality issues: %s", quality_issues)
report_filename = f"{report_type}_report_{datetime.utcnow().strftime('%Y%m%d')}.md"
report_path = os.path.join(output_dir, report_filename)
with open(report_path, "w", encoding="utf-8") as f:
f.write(rendered)
logger.info("Report saved to %s", report_path)
return {
"report_type": report_type,
"output_path": report_path,
"tlp": data.get("tlp", "AMBER"),
"validation_errors": validation_errors,
"quality_issues": quality_issues,
"rendered_length": len(rendered),
}
def main():
parser = argparse.ArgumentParser(description="Threat Intelligence Report Generator")
parser.add_argument("--type", required=True, choices=list(REPORT_TEMPLATES.keys()),
help="Report type: strategic, operational, tactical, flash")
parser.add_argument("--data", required=True, help="Path to JSON data file with report content")
parser.add_argument("--output-dir", default=".", help="Output directory")
parser.add_argument("--output", default="report_meta.json")
args = parser.parse_args()
os.makedirs(args.output_dir, exist_ok=True)
result = generate_report(args.type, args.data, args.output_dir)
out_path = os.path.join(args.output_dir, args.output)
with open(out_path, "w") as f:
json.dump(result, f, indent=2)
logger.info("Metadata saved to %s", out_path)
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()