s0u9ata/security-kg
Security Knowledge Graph Triples Security data from 24 sources represented as Subject-Predicate-Object (SPO) triples in Parquet format, ready for knowledge-graph construction, graph-ML, RAG pipelines, and threat-intelligence analysis. Sources: ATT&CK · CAPEC · CWE · CVE · CPE · D3FEND · ATLAS · CAR · ENGAGE · F3 · EPSS · KEV · Vulnrichment · GHSA · Sigma · ExploitDB · MISP Galaxies · LOLBAS · LOLDrivers · Atomic Red Team · NIST 800-53 · Nuclei · EUVD · OSV Last updated:… See the full description on the dataset page: https://huggingface.co/datasets/s0u9ata/security-kg.
Security Knowledge Graph Triples
Security data from 24 sources represented as Subject-Predicate-Object (SPO) triples in Parquet format, ready for knowledge-graph construction, graph-ML, RAG pipelines, and threat-intelligence analysis.
Sources: ATT&CK · CAPEC · CWE · CVE · CPE · D3FEND · ATLAS · CAR · ENGAGE · F3 · EPSS · KEV · Vulnrichment · GHSA · Sigma · ExploitDB · MISP Galaxies · LOLBAS · LOLDrivers · Atomic Red Team · NIST 800-53 · Nuclei · EUVD · OSV
Last updated: 2026-09-21T11:59:25Z
Quick Start
from datasets import load_dataset
ds = load_dataset("s0u9ata/security-kg", "enterprise")
print(ds["train"][0])
# {'subject': 'T1059.001', 'predicate': 'rdf:type', 'object': 'Technique', 'source': 'attack', 'object_type': 'enum', 'meta': ''}Configurations
Knowledge Graph Structure
Group Campaign
\ /
uses
|
v
TECHNIQUE -----> Tactic
^ ^ ^
| | |
| | +-- D3FEND (counters)
| | +-- CAR (detects)
| | +-- Sigma (detects)
| | +-- ENGAGE (engages)
| | +-- F3 (fraud techniques)
| | +-- ATLAS (related)
| | +-- MISP Galaxies (cross-refs)
| | +-- LOLBAS (maps-to)
| | +-- LOLDrivers (maps-to)
| | +-- Atomic Red Team (tests)
| | +-- NIST 800-53 (mitigates)
| |
| +-- Mitigation (mitigates)
| +-- DataComponent (detects)
|
+-- maps-to -- CAPEC
|
related-weakness
|
v
CWE
^
|
related-weakness
|
CVE ----> CPE
^
|
EPSS (score)
KEV (exploited)
GHSA (advisory)
Vulnrichment (SSVC)
ExploitDB (exploit)
Nuclei (detection template)
EUVD (EU advisory)
OSV (open-source vuln)Schema
Each row is an enriched triple with six string columns:
Predicate Reference
ATT&CK Entity Properties
ATT&CK Relationship Predicates
CAPEC Predicates
CWE Predicates
CVE Predicates
CPE Predicates
D3FEND Predicates
ATLAS Predicates
CAR Predicates
ENGAGE Predicates
F3 Predicates
EPSS Predicates
KEV Predicates
Vulnrichment Predicates
GHSA Predicates
Sigma Predicates
ExploitDB Predicates
MISP Galaxy Predicates
LOLBAS Predicates
LOLDrivers Predicates
Atomic Red Team Predicates
NIST 800-53 Predicates
Nuclei Predicates
EUVD Predicates
OSV Predicates
Dataset Creation
Source Data
Conversion Pipeline
The converter downloads source data, extracts entity property triples and relationship triples, and writes them as Parquet files. The source code and full documentation are at:
[github.com/S0UGATA/security-kg](https://github.com/S0UGATA/security-kg)
To regenerate or update this dataset:
git clone https://github.com/S0UGATA/security-kg.git
cd security-kg
pip install -r requirements.txt
python src/convert.pyThis produces fresh Parquet files in output/ from the latest data across all 24 sources.
Visualizer
Explore the Parquet files interactively at security-kg-viz.
Pre-computed neighborhoods (neighborhoods/)
For the most-connected entities in combined.parquet, this dataset ships pre-rendered multi-hop neighborhood JSONs the visualizer can fetch directly, skipping the DuckDB-WASM + Parquet path entirely for hot lookups:
neighborhoods/
T1059.json # array of Triple objects (depth=2, limit=500)
T1059.001.json
CVE-2024-1234.json
CAPEC-100.json
...
index.json # { source, fingerprint, depth, limit, entities: [...] }Each <entity>.json is the same shape the viz already builds from q.entityNeighborhood() — an array of {subject, predicate, object, source, object_type, object_canonical}. Filenames use a reversible slug (characters outside [A-Za-z0-9._-] are _xx hex-escaped); index.json is the authoritative mapping from entity → filename and includes a parquet fingerprint for cache invalidation. The bundle is regenerated each weekly refresh whenever combined.parquet changes.
Use Cases
- Knowledge Graph Construction: Load triples into Neo4j, RDFLib, or NetworkX for graph queries
- Graph ML: Train graph neural networks (GNNs) on security data structure for link prediction
- RAG / LLM Grounding: Use triples as structured context for retrieval-augmented generation
- Threat Intelligence: Query relationships between groups, techniques, vulnerabilities, and mitigations
- Vulnerability Prioritization: Combine SSVC, EPSS, KEV, and ExploitDB data for risk-based triage
- Defensive Gap Analysis: Find heavily-used ATT&CK techniques with insufficient detection coverage
- Supply Chain Risk: Score open-source packages by linking GHSA advisories to CVE/EPSS/KEV enrichment
- Security Automation: Programmatically map detections to techniques to tactics
Cross-Source Analysis Notebook
The repository includes a Jupyter notebook with 16 cross-source analyses and visualizations built on combined.parquet — covering SSVC patch prioritization, defensive gap analysis, kill chain tactic coverage, exploit weaponization timelines, ransomware CWE pipelines, supply chain package risk, and more.
Example Queries
SSVC Patch Prioritization (Vulnrichment + EPSS + KEV)
import pandas as pd
from datasets import load_dataset
# Load combined graph for cross-source queries
ds = load_dataset("s0u9ata/security-kg", "combined")
df = ds["train"].to_pandas()
# Build SSVC triage matrix: exploitation status × automatable × EPSS score
ssvc = df[df.predicate == "ssvc-exploitation"][["subject", "object"]].rename(columns={"object": "exploitation"})
auto = df[df.predicate == "ssvc-automatable"][["subject", "object"]].rename(columns={"object": "automatable"})
epss = df[df.predicate == "epss-score"][["subject", "object"]].copy()
epss["epss"] = epss.object.astype(float)
triage = ssvc.merge(auto, on="subject").merge(epss[["subject", "epss"]], on="subject")
# Highest priority: actively exploited + automatable + high EPSS
critical = triage[(triage.exploitation == "active") & (triage.automatable == "yes") & (triage.epss > 0.9)]
print(f"Immediate action: {len(critical)} CVEs")Defensive Gap Analysis (ATT&CK + Sigma + D3FEND + CAR)
# Find ATT&CK techniques heavily used by APT groups but poorly covered by detections
uses = df[(df.predicate == "uses") & df.subject.str.startswith("G")]
group_usage = uses.groupby("object").subject.nunique().rename("groups_using")
# Count detection sources per technique (Sigma + CAR + D3FEND + ENGAGE)
sigma = df[df.predicate == "detects-technique"].groupby("object").subject.nunique().rename("detections")
d3fend = df[df.predicate == "restricts"].groupby("object").subject.nunique().rename("defenses")
coverage = pd.DataFrame(group_usage).join(sigma).join(d3fend).fillna(0)
gaps = coverage[(coverage.groups_using > 10) & (coverage.detections < 5)]
print(f"High-usage, low-detection techniques: {len(gaps)}")Supply Chain Risk (GHSA + CVE + EPSS + KEV + ExploitDB)
# Score open-source packages by aggregating risk from linked CVEs
ghsa_cve = df[df.predicate == "related-cve"][["subject", "object"]].rename(columns={"subject": "ghsa", "object": "cve"})
packages = df[df.predicate == "affects-package"][["subject", "object"]].rename(columns={"subject": "ghsa", "object": "pkg"})
epss_scores = df[df.predicate == "epss-score"][["subject", "object"]].copy()
epss_scores["epss"] = epss_scores.object.astype(float)
kev_cves = set(df[(df.predicate == "rdf:type") & (df.object == "KnownExploitedVulnerability")].subject)
exploit_cves = set(df[df.predicate == "exploits-cve"].object)
# Join package → GHSA → CVE → enrichment
risk = packages.merge(ghsa_cve, on="ghsa").merge(epss_scores[["subject", "epss"]], left_on="cve", right_on="subject")
risk["in_kev"] = risk.cve.isin(kev_cves)
risk["has_exploit"] = risk.cve.isin(exploit_cves)
risk["ecosystem"] = risk.pkg.str.split("/").str[0]
# Top ecosystems by high-risk CVE count
high_risk = risk[(risk.epss > 0.5) | risk.in_kev | risk.has_exploit]
print(high_risk.groupby("ecosystem").cve.nunique().sort_values(ascending=False).head(10))CAPEC → CWE → CVE (Attack Pattern Chain)
capec = load_dataset("s0u9ata/security-kg", "capec")["train"].to_pandas()
cve = load_dataset("s0u9ata/security-kg", "cve")["train"].to_pandas()
# Find CWEs related to SQL Injection (CAPEC-66)
cwe_ids = capec[(capec.subject == "CAPEC-66") & (capec.predicate == "related-weakness")].object.tolist()
# Find CVEs with those CWEs
for cwe_id in cwe_ids:
related_cves = cve[(cve.predicate == "related-weakness") & (cve.object == cwe_id)].subject.unique()
print(f"{cwe_id}: {len(related_cves)} CVEs")D3FEND (Defensive Taxonomy)
ds = load_dataset("s0u9ata/security-kg", "d3fend")
df = ds["train"].to_pandas()
# All 497 defensive techniques in the D3FEND taxonomy
defenses = df[(df.predicate == "rdf:type") & (df.object == "DefensiveTechnique")]
print(f"Defensive techniques: {len(defenses)}")
# Find children of a category (e.g., all techniques under Network Traffic Analysis)
children = df[(df.predicate == "child-of") & (df.object == "NetworkTrafficAnalysis")].subject.tolist()
# Get their names
names = df[df.predicate == "name"][["subject", "object"]]
print(names[names.subject.isin(children)].to_string(index=False))Source Licensing & Attribution
This dataset is published under the Apache 2.0 license. The underlying source data is provided under various licenses as detailed below. By using this dataset, you agree to comply with each source's respective terms.
License
Apache 2.0 — see Source Licensing & Attribution for individual source terms.
