Understanding HCL Syntax
Threatcl uses HCL (HashiCorp Configuration Language) as its foundation ‐ a structured configuration language that's easy to read, easy to write, and version-control friendly. This guide covers the full threatcl specification.
Why HCL for Threat Modeling?
- Human-readable ‐ Easy to write and review in any text editor
- Version control friendly ‐ Clean diffs, works great with Git
- DevOps familiar ‐ Same language family as Terraform
- Structured ‐ Enforces consistency across teams
- Composable ‐ Variables, and imports for reuse
Minimum Valid File
A valid .hcl file requires three things: a spec_version string, at least one threatmodel block with a name, and an author string within it.
spec_version = "0.2.4"
threatmodel "My Application" {
author = "@yourname"
}
Basic Structure
HCL files consist of blocks and arguments. Blocks use the syntax type [label] { ... } and contain arguments (key = value pairs) or other nested blocks.
# This is a comment
spec_version = "0.2.4"
# Block with a label
threatmodel "My Application" {
# Arguments (key = value pairs)
description = "My application threat model"
author = "@security-team"
link = "https://wiki.example.com/myapp"
# Nested block
additional_attribute "environment" {
value = "production"
}
}
Arguments assign values with key = value . Values can be strings ("text" ), numbers (50 ), booleans (true /false ), or lists (["a", "b"] ).
Comments use # or // for single-line, and /* */ for multi-line.
Core Blocks Reference
threatmodel
The root block for your threat model. Requires a unique name label. Contains all other blocks. You can have multiple threatmodel blocks per file, each with a unique name.
threatmodel "E-commerce Platform" {
description = "Customer-facing online shopping system"
author = "@security-team"
link = "https://wiki.example.com/ecommerce"
diagram_link = "https://wiki.example.com/ecommerce/dfd.png"
attributes {
new_initiative = "true"
internet_facing = "true"
initiative_size = "Small"
}
additional_attribute "compliance" {
value = "PCI-DSS"
}
additional_attribute "business_unit" {
value = "Retail"
}
}
The attributes block has three standard fields: new_initiative , internet_facing , and initiative_size (Undefined, Small, Medium, or Large).
Use additional_attribute blocks for any custom metadata your organization needs. Each requires a unique label and a value string.
information_asset
Define data that needs protection. Each requires a unique name label. information_classification must be one of Public , Confidential , or Restricted .
information_asset "credit_cards" {
description = "Customer payment card information"
information_classification = "Restricted"
source = "User input via payment form"
}
information_asset "user_accounts" {
description = "User profile and credentials"
information_classification = "Confidential"
}
usecase
Describe how users interact with the system. Multiple blocks allowed, no labels ‐ just a description .
usecase {
description = "Customer places an order"
}
usecase {
description = "Customer views order history"
}
usecase {
description = "Administrator manages user accounts"
}
exclusion
Define what is explicitly out of scope for this threat model.
exclusion {
description = "Third-party payment processor internals"
}
exclusion {
description = "Mobile application (covered in separate model)"
}
third_party_dependency
Document external services and their criticality. Each requires a unique name label.
third_party_dependency "stripe" {
description = "Payment processing service"
uptime_dependency = "hard"
uptime_notes = "Cannot process orders without Stripe"
saas = true
paying_customer = true
}
third_party_dependency "auth_provider" {
description = "OAuth2 authentication provider"
uptime_dependency = "degraded"
uptime_notes = "Users cannot log in, but existing sessions work"
saas = true
}
uptime_dependency values:
hard‐ System fails completely without itdegraded‐ System works with reduced functionalityoperational‐ System works but operations are impactednone‐ Optional dependency
threat & control
Identify security threats. Each threat has a unique name label and can contain nested control blocks that mitigate it. Controls are always defined inside their parent threat.
threat "SQL Injection" {
description = "Attacker injects SQL via search functionality"
impacts = ["Confidentiality", "Integrity"]
stride = ["Tampering", "Info Disclosure"]
information_asset_refs = ["credit_cards", "user_accounts"]
control "input_validation" {
description = "Validate and sanitize all user input"
implemented = true
implementation_notes = "Using OWASP ESAPI library v3.2.0"
risk_reduction = 80
}
control "parameterized_queries" {
description = "Use parameterized queries for all DB access"
implemented = true
implementation_notes = "All queries use prepared statements"
risk_reduction = 90
}
}
threat "Session Hijacking" {
description = "Attacker steals user session tokens"
impacts = ["Confidentiality"]
stride = ["Spoofing"]
information_asset_refs = ["user_accounts"]
control "secure_cookies" {
description = "HttpOnly, Secure, SameSite flags on all cookies"
implemented = true
}
control "session_timeout" {
description = "Sessions expire after 30 minutes of inactivity"
implemented = false
implementation_notes = "TODO: Implement in v1.2.0"
}
}
STRIDE values:
Spoofing, Tampering, Repudiation, Info Disclosure, Denial of Service, Elevation of Privilege
impacts values:
Confidentiality, Integrity, Availability
Data Flow Diagrams
Threatcl can automatically generate data flow diagrams. A DFD block contains process , data_store , and external_element blocks, connected by flow blocks. Group elements inside trust_zone blocks to define security boundaries.
data_flow_diagram_v2 "web_app_dfd" {
trust_zone "internet" {
external_element "user" {}
}
trust_zone "dmz" {
process "web_app" {}
process "api_gateway" {}
}
trust_zone "internal" {
process "backend" {}
data_store "database" {
information_asset = "user_accounts"
}
}
flow "user_request" {
from = "user"
to = "web_app"
}
flow "api_call" {
from = "web_app"
to = "api_gateway"
}
flow "backend_query" {
from = "api_gateway"
to = "backend"
}
flow "db_query" {
from = "backend"
to = "database"
}
}
Tip: Threatcl Cloud will automatically render these diagrams in the web interface. Element names (process , data_store , external_element ) must be globally unique within a DFD. Data stores can reference information_asset blocks by name.
Advanced Features
Variables
Define reusable values outside the threatmodel block. Reference them with var.name directly or via string interpolation with ${var.name} .
variable "team" {
value = "platform-security"
}
variable "environment" {
value = "production"
}
threatmodel "My App" {
author = var.team
description = "Threat model for ${var.environment}"
}
Complete Example
Here's a complete threat model putting it all together:
spec_version = "0.2.4"
threatmodel "Tower of London" {
description = "A historic castle"
author = "@xntrik"
attributes {
new_initiative = "true"
internet_facing = "true"
initiative_size = "Small"
}
information_asset "crown jewels" {
description = "including the imperial state crown"
information_classification = "Confidential"
}
usecase {
description = "The Queen can fetch the crown"
}
threat "Crown Theft" {
description = "Someone who isn't the Queen steals the crown"
impacts = ["Confidentiality"]
control "Guards" {
description = "Trained guards patrol tower"
risk_reduction = 75
}
}
}