attack-flow — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited attack-flow (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Generate SITF-compliant attack flow JSON files from attack descriptions or incident reports.
/attack-flow <attack-name> [source]attack-name: Identifier for the attack (e.g., "s1ngularity", "solarwinds")source: URL, local file path (report, write-up), "websearch" for auto-research, or omit to use conversation context. A name plus a document ("X, and use this report to augment") means: research X and fold in the documentArguments: $ARGUMENTS
When this skill is invoked:
techniques.json to get the full technique library."type": "technique-gap"/technique-proposal should be run for in-scope gapscustomLabel and connect the entry point directly to the first in-scope technique.customLabel with "Contributing:" and say in evidence that it is not an attacker actionevidence of the technique that uses it, or as a single technique (e.g. T-V008) in the relevant component. Do NOT create a separate zone for it; zones are for victims.[Inference] in evidenceApply these layout rules:
#### Rule 1: Component Layout (Left-to-Right by Attack Flow)
#### Rule 2: Technique Ordering (Top-to-Bottom)
#### Rule 3: Technique-Component Centering
technique.x = component.x + (component.width - technique.width) / 2#### Rule 4: Component Sizing
#### Rule 5: Edge Connections
top target handle and a bottom source handle (app/visualizer.html). Entry points expose right/bottom sources, exit points left/top targetssourceHandle: "bottom", targetHandle: "top" within a component. For cross-component edges, right/left is the convention, but on technique nodes it falls back to bottom/top. Don't design layouts that rely on side connections"type": "smoothstep" for all edges#### Rule 6: Edge Labels (Minimal)
"label": "")customLabel / evidence, never on edgesGenerate the attack flow JSON with this exact structure:
{
"metadata": {
"name": "Attack Name",
"title": "Canvas Display Title",
"created": "ISO-8601 timestamp",
"version": "1.0",
"framework": "SITF",
"description": "Brief attack description"
},
"nodes": [],
"edges": []
}Metadata field guidelines:
name: Short identifier (e.g., "tj-actions", "circleci")title: Concise canvas title, max 5-7 words (e.g., "tj-actions/changed-files Compromise", "CircleCI Security Incident (2023)")description: One sentence summary, max 150 characters#### Node Structure - Entry Point
{
"id": "entryPoint-attackname-1",
"type": "entryPoint",
"position": { "x": -150, "y": 200 },
"data": {
"label": "Entry Point Label"
},
"zIndex": 10,
"width": 195,
"height": 46
}#### Node Structure - Component
{
"id": "component-cicd-1",
"type": "component",
"position": { "x": 50, "y": 80 },
"data": {
"label": "CI/CD",
"componentId": "cicd",
"techniques": [],
"customLabel": "Context-specific label"
},
"zIndex": -1,
"width": 250,
"height": 500,
"style": { "width": 250, "height": 500 }
}#### Node Structure - Technique (CRITICAL: use exact field names)
{
"id": "technique-c003-1",
"type": "technique",
"position": { "x": 95, "y": 160 },
"data": {
"id": "T-C003",
"name": "PWN Request / Poisoned Pipeline Execution",
"component": "cicd",
"stage": "Initial Access",
"description": "Full description from techniques.json",
"risks": ["risk1", "risk2"],
"controls": {
"protective": [{ "name": "control1", "frameworks": {...} }],
"detective": [{ "name": "control2", "frameworks": {...} }]
},
"customLabel": "Attack-specific context",
"evidence": "Optional: specific evidence from the attack"
},
"zIndex": 10,
"width": 160,
"height": 96
}IMPORTANT technique.data fields:
id: Use technique ID (e.g., "T-C003") — NOT "techniqueId"name: Use technique name — NOT "label"risks: Copy full array from techniques.jsoncontrols: Copy full object with protective and detective arrays from techniques.jsoncustomLabel: Add attack-specific context (e.g., "PRs #18018, #18020")evidence: Optional field for attack-specific evidence#### Node Structure - Exit Point
{
"id": "exitPoint-attackname-1",
"type": "exitPoint",
"position": { "x": 950, "y": 200 },
"data": {
"label": "Secondary Supply Chain Attack"
},
"zIndex": 10,
"width": 144,
"height": 46
}#### Edge Structure (with full styling)
{
"id": "edge-source-target",
"source": "technique-c003-1",
"sourceHandle": "bottom",
"target": "technique-c004-1",
"targetHandle": "top",
"type": "smoothstep",
"animated": false,
"markerEnd": { "type": "arrowclosed" },
"label": "",
"labelStyle": { "fill": "#DC2626", "fontWeight": 600, "fontSize": 10 },
"labelBgStyle": { "fill": "#FFFFFF", "fillOpacity": 0 }
}#### Cross-component Edge (with gray styling)
{
"id": "edge-cross-component",
"source": "technique-c011-1",
"sourceHandle": "right",
"target": "technique-r001-1",
"targetHandle": "left",
"type": "smoothstep",
"animated": false,
"style": { "stroke": "#9ca3af" },
"markerEnd": { "type": "arrowclosed", "color": "#9ca3af" },
"label": "Tokens",
"labelStyle": { "fill": "#DC2626", "fontWeight": 600, "fontSize": 10 },
"labelBgStyle": { "fill": "#FFFFFF", "fillOpacity": 0 }
}#### Contributing-condition Edge (dashed) Same as the cross-component edge, with "style": { "stroke": "#9ca3af", "strokeDasharray": "5,5" } and usually "label": "". Also used for attacker infrastructure the payload depends on (e.g. a C2 dead drop). See flows/incidents/trivy-act-ii.json.
Node types:
entryPoint: Attack entry (Phishing, Vulnerability Exploit, Stolen Credentials, Malicious Fork PR, etc.)component: SITF component container (endpoint, vcs, cicd, registry, production)technique: Attack technique from techniques.jsontechnique-gap: Placeholder for missing technique (flag for /technique-proposal)exitPoint: Attack outcome (Future Breach, Persistence, Secondary Supply Chain Attack, etc.)victimZone: Visual container grouping components belonging to a single victim organization#### Victim Zones (Multi-Organization Attacks)
When an attack involves multiple victim organizations (e.g., supply chain attacks that cascade across vendors), use victimZone nodes to visually group each victim's components.
When to use victim zones:
Victim Zone Structure:
{
"id": "victimZone-aqua",
"type": "victimZone",
"position": { "x": -24, "y": 15 },
"data": {
"label": "Aqua Security",
"color": "#3B82F6"
},
"zIndex": -10,
"width": 1444,
"height": 945,
"style": { "width": 1444, "height": 945 }
}Layout rules for victim zones:
#3B82F6 blue, #06B6D4 cyan, #8B5CF6 purple)zIndex: -10 so zones render behind components and techniquesReference: See flows/incidents/teampcp-campaign.json for a multi-victim example with 4 victim zones.
After generating the flow, analyze defensive gaps:
| Technique | Missing Control | Type | OWASP SPVS |
|-----------|-----------------|------|------------|
| T-C003 | Minimal workflow permissions | Protective | V3.1 |
| T-C005 | Log sanitization | Protective | V2.5 |
| T-C005 | Runtime agent on runner | Detective | V5.4 |Run this checklist before outputting:
[ ] Valid JSON structure (parse test passes)
[ ] Required fields present: metadata.{name,title,created,version,framework}, nodes[], edges[]
[ ] All node IDs are unique
[ ] All edge source/target reference valid node IDs
[ ] Technique nodes use data.id and data.name (NOT techniqueId/label)
[ ] Technique nodes include full risks[] array and controls object with protective/detective arrays
[ ] Out-of-scope attack steps noted but not forced into SITF techniques
[ ] All techniques centered within components (x = component.x + 45 for width=250)
[ ] Component heights are adequate (minimum 500px)
[ ] Techniques ordered by attack flow sequence
[ ] Initial Access techniques appear first when order is ambiguous
[ ] All technique IDs exist in techniques.json OR flagged as technique-gap
[ ] Exit points connected to terminal techniques
[ ] No orphaned nodes: every non-entry node has an incoming edge, EXCEPT roots whose customLabel marks them as "Contributing:" or attacker preparation
[ ] Edges have sourceHandle, targetHandle, markerEnd, labelStyle, labelBgStyle
[ ] Edge labels: at most 3-5 non-empty, each 1-2 words, transparent background
[ ] Downstream consumer types each mapped or noted "not observed" (package/image compromises)
[ ] Source conflicts and inferred steps flagged in outputflows/incidents/<attack-name>.jsonpython3 -c "import json; json.load(open('file'))"## Attack Flow: <attack-name>
### Attack Chain
1. Initial Access via [entry point]
2. [Technique] → [Technique] → ...
3. Impact: [exit point]
### Techniques Used
| ID | Name | Component | Stage |
|----|------|-----------|-------|
| T-C003 | PWN Request | CI/CD | Initial Access |
| ... | ... | ... | ... |
### Control Gaps Identified
| Missing Control | Type | Would Prevent | OWASP SPVS |
|-----------------|------|---------------|------------|
| Minimal workflow permissions | Protective | T-C003 | V3.1 |
| ... | ... | ... | ... |
### Out-of-Scope Steps
- [Step X]: Generic cloud attack, see MITRE ATT&CK T1078
### Technique Gaps
- [Step Y]: No matching SITF technique, run `/technique-proposal`/technique-proposalUsers often adjust the layout in the visualizer and save over the file, then ask for more changes.
metadata.name to "Attack Flow" and drops title/description. Check the metadata after every user save and restore it/attack-flow ultralytics websearchThis will:
flows/incidents/ultralytics.jsonSee flows/incidents/ultralytics.json or flows/incidents/tj-actions.json for correctly structured examples.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.