Skip to content

Threatmodel block

Each threatcl hcl file has to include one more unique threatmodel blocks.

threatmodel attributes

AttributeTypeReq’dDescription
NAMElabel string Specifies the name of the threat model
authorstring Specifies the author of the threat model
descriptionstringDescribes the threat model
linkstringAn href to other documentation
diagram_linkstringAn href to a diagram. (see diagram_link)
repositoryarray [string]Source code repositories this model covers. See repository
idstringA stable, identifier-safe handle for this model. See id
extendsstringInherit content from another threat model. See extends
created_atintegerCreation UNIX timestamp
updated_atintegerUpdated UNIX timestamp
attributesblockSee attributes
additional_attributesblockSee additional_attributes
usecaseblockSee usecase
exclusionblockSee exclusion
third_party_dependencyblockSee third_party_dependency
information_assetblockSee information_asset
threatblockSee threat
data_flow_diagram_v2blockSee data_flow_diagram_v2
mermaidblockSee mermaid
includingstringSee including
importsarray [string]See imports

If it ends in .jpg or .png then it will be embedded in the resultant dashboard. If this isn’t set, but there is a data flow diagram, this will be automatically generated and included when running threatcl dashboard

repository

An optional list of source code repositories that this threat model covers. Each entry is a full URL, scheme included, so a single model can point at more than one repository.

repository = [
"https://github.com/example/api",
"https://github.com/example/worker",
]

Repositories render as a ## Repositories section in markdown output, are inherited by a threat model that pulls this one in with including, and are exported under project.attributes.repository in OTM.

id

An optional, identifier-safe handle for the threat model. Names are arbitrary strings, so they can’t be used in dotted references. An id gives the model a stable address that survives a rename.

threatmodel "Tower of London" {
id = "tower_of_london"
author = "@xntrik"
}

Each segment must be lowercase letters, digits or underscores, and start with a letter. Ids may be dot-separated to namespace a model beneath a parent (buildings.tower) and must be unique across every file parsed together. When you don’t declare one, an identifier is derived from the name ("Tower of London"tower_of_london); only a declared id is rename-stable.

See Multiple Files for namespacing rules, and Invariants for where these addresses are used.

extends

An optional attribute naming another threat model’s declared id. The extending model inherits that model’s threat, information_asset, usecase, exclusion and third_party_dependency blocks, plus its attributes block when the child declares none.

threatmodel "Base controls" {
id = "base"
author = "@xntrik"
threat "Credential stuffing" {
description = "Attackers replay leaked credentials"
}
}
threatmodel "Payments" {
id = "base.payments"
extends = "base"
author = "@xntrik"
}

Same-named items declared on the child win over the inherited ones. Scalars (description, link, and friends), data flow diagrams and mermaid diagrams are deliberately not inherited, they stay per-model. Chains resolve parent-first, and both cycles and unknown targets are parse errors.

See Multiple Files for using extends across separate files.

attributes

The attributes block is optional, but recommended. It includes the following attributes.

AttributeTypeRequiredDescription
new_initiativeboolean Whether this is a new project
internet_facingboolean Whether this system is exposed to the Internet
initiative_sizestring Undefined, Small, Medium, Large

additional_attributes

Your threatmodel may include multiple additional_attributes blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string The name of the attribute
valuestring The value of the attribute

usecase

Your threatmodel may include multiple usecase blocks. These don’t have labels or identifiers. It includes the following attribute.

AttributeTypeRequiredDescription
descriptionstring A description of the system’s use case

exclusion

Your threatmodel may include multiple exclusion blocks. These don’t have labels or identifiers. It includes the following attribute.

AttributeTypeRequiredDescription
descriptionstring Define of out-of-scope exclusions of the threatmodel

third_party_dependency

Your threatmodel may include multiple third_party_dependency blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string The name of the 3rd party dep
descriptionstring A description of the 3rd party dep
uptime_dependencystring none, degraded, hard, operational
saasbooleanIs this a SaaS dep?
paying_customerbooleanAre we paying for it?
open_sourcebooleanIs this OSS?
infrastructurebooleanIs this Infra?
uptime_notesstringNotes about what happens if unavailable

information_asset

Your threatmodel may include multiple information_asset blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string The name of the asset
descriptionstringDescribe the asset
information_classificationstring Public, Confidential, Restricted
sourcestringWhere was block sourced from
i.e. terraform
refstringA reference to a library item. See ref

threat

Your threatmodel may include multiple threat blocks, with unique labels. Two threats in the same threat model can’t share a name. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string The name of the threat
descriptionstring Describe the threat
impactsarray [string]Confidentiality, Integrity, Availability
stridearray [string]Spoofing,
Tampering,
Repudiation,
Info Disclosure,
Denial of Service,
Elevation of Privilege
information_asset_refsarray [string]Refer to information_asset blocks. See Referring to Elements
controlblockSee control
control_importsarray [string]Allows you to import full expanded control blocks. See imports
riskblockRate this threat’s likelihood and impact. See risk
refstringA reference to a library item. See ref

risk

Each threat may include a single optional risk block, rating the threat before controls are considered. threatcl derives a severity and a 0-100 score from that rating, then a residual view that factors in the risk_reduction of every implemented control.

threat "Credential stuffing" {
description = "Attackers replay leaked credentials against the login endpoint"
risk {
likelihood = "high"
impact = "very_high"
rationale = "Credentials for this user base appear in known breach corpora"
}
control "MFA" {
description = "Multi-factor authentication on all accounts"
implemented = true
risk_reduction = 80
}
}
AttributeTypeRequiredDescription
likelihoodstring very_low, low, medium, high, very_high
impactstring very_low, low, medium, high, very_high
severitystringOverride the computed severity: info, low, medium, high, critical
rationalestringFree text explaining the rating

likelihood and impact are normalised, so "Very High", "very-high" and "very_high" all mean the same thing.

Severity matrix

Unless you set severity explicitly, it’s computed from likelihood x impact:

Likelihood \ Impactvery_lowlowmediumhighvery_high
very_highlowmediumhighcriticalcritical
highlowmediumhighhighcritical
mediumlowlowmediumhighhigh
lowinfolowlowmediumhigh
very_lowinfoinfolowlowmedium

Scores and residual risk

Each level also carries a numeric weight (very_low 10, low 30, medium 50, high 75, very_high 95) and the inherent score is those two weights multiplied as percentages, back onto a 0-100 scale. A high likelihood with a very_high impact scores 0.75 x 0.95, or 71.2.

The residual score applies the risk_reduction of every implemented control to that inherent score, with diminishing returns: two controls reducing risk by 50% each leave 25% of the risk, not 0%. Unimplemented controls don’t reduce anything. The residual score maps onto a band of its own: 75+ is critical, 50+ high, 25+ medium, 10+ low, below that info.

The threat above renders in threatcl view and threatcl dashboard as:

> Risk: Likelihood _high_ × Impact _very_high_ → Inherent Severity **critical** (score 71.2)
>
> Credentials for this user base appear in known breach corpora
> Residual Risk (after implemented controls): score 14.2 (**low**, 80% reduced)

Risk ratings are also exposed by the GraphQL API, and likelihood/impact map onto a threat’s risk object when exporting to OTM.

control

Your threat blocks may include multiple control blocks, with unique labels. Two controls within the same threat can’t share a name. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string The name of the control
descriptionstring Describe the control
implementedbooleanIs it implemented?
implementation_notesstringDescribe the implementation
risk_reducationintegerHow much this control reduces risk
refstringA reference to a library item. See ref
attributeblockSee attribute

attribute

Your expanded_control blocks may include multiple attribute blocks, with unique labels. It includes the following attribute.

AttributeTypeRequiredDescription
NAMElabel string The name of the attribute
valuestring The value of the attribute

data_flow_diagram_v2

Your threatmodel may include multiple data_flow_diagram_v2 blocks, with unique labels. It includes the following attributes.

Unlike other blocks, when you define a process, data_store, or external_element they must have a globally unique label, for that particular dfd. For example, you can’t have a process and data_store called “foo”.

Elements refer to each other by label; a flow’s from and to, a data store’s information_asset, an element’s trust_zone. Each of those also accepts a slug or a dotted expression, such as process.web_app. See Referring to Elements.

AttributeTypeRequiredDescription
NAMElabel string dfd name
processblockSee process
data_storeblockSee data_store
external_elementblockSee external_element
trust_zoneblockSee trust_zone
flowblockSee flow

process

Your data_flow_diagram_v2 block may include multiple process blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string process name
trust_zonestringdefines a trust boundary / zone

data_store

Your data_flow_diagram_v2 block may include multiple data_store blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string data store name
trust_zonestringdefines a trust boundary / zone
information_assetstringrefers back to a previous information_asset block ref

external_element

Your data_flow_diagram_v2 block may include multiple external_element blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string external element name
trust_zonestringdefines a trust boundary / zone

trust_zone

Your data_flow_diagram_v2 block may include multiple trust_zone blocks, with unique labels. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string trust zone name
processblocksee process
data_storeblocksee data_store
external_elementblocksee external_element

flow

Your data_flow_diagram_v2 block may include multiple flow blocks. A flow must have a label, but it doesn’t have to be unique. But, the from and to attributes must be unique. It includes the following attributes.

AttributeTypeRequiredDescription
NAMElabel string flow title
fromstring refer to a process, external_element or data_store
tostring refer to a process, external_element or data_store
protocolstringan optional protocol

mermaid

Your threatmodel may include multiple mermaid blocks, with unique labels, for embedding free-form mermaid diagrams. Unlike data_flow_diagram_v2, which threatcl draws for you from elements and flows. A mermaid block carries raw mermaid source verbatim, so any diagram type works.

mermaid "Login sequence" {
description = "How a user authenticates"
content = <<-EOT
sequenceDiagram
User->>App: credentials
App->>Auth: verify
Auth-->>App: token
EOT
}
AttributeTypeRequiredDescription
NAMElabel string The diagram’s title
contentstring The raw mermaid source. A heredoc is the idiomatic form
descriptionstringDescribe the diagram

There’s no type or engine attribute, mermaid infers the diagram type from the first line of content.

These render into the markdown produced by threatcl dashboard and threatcl view, and are carried through the json, hcl and OTM exports. To pull the raw source back out (to pipe into a renderer such as mmdc, for instance) use the threatcl mermaid command.

including

Each threatmodel may optionally include an including attribute string that refers to a single other threatcl hcl file.

In this file must be a single, valid threatmodel block.

This included threatmodel will form the base of this new threatmodel. Any duplicate fields in the parent threat model will overwrite those from the included.

See External HCL Files for more information on how to refer to external files.

imports

Each threatmodel may optionally include an imports attribute with an array of string values that refer to other hcl files.

These files are used to centrally define various attributes that you can then refer to in your threatmodel. Currently we only support the definition of “control” components.

An example import file may look like:

controls.hcl
component "control" "control_name" {
description = "A control that can be used in multiple places"
}
component "control" "authentication_control" {
description = "Multi-factor authentication required"
implemented = true
implementation_notes = "Using TOTP for all admin accounts"
risk_reduction = 80
attribute "category" {
value = "Authentication"
}
attribute "framework" {
value = "NIST"
}
}

To use these imports, you reference to the string value like this:

threatmodel.hcl
threatmodel "tm" {
author = "@xntrik"
description = "A threat model"
imports = ["controls.hcl"]
threat {
description = "Something bad"
expanded_control "control" {
description = import.control.control_name.description
}
}
}

You can also use string interpolation as well, so for instance:

description = "Some text that and ${import.control.control_name.description}"

Technically you can use these import values similar to Variables

To use the more complex, multi-attribute control component, such as authentication_control above, you use the control_imports string array inside a threat block. For example, to import the authentication_control from above:

threat {
description = "Authentication is bypassed"
control_imports = ["import.control.authentication_control"]
}

When this is Viewed, or Exported, that threat will include that external Expanded Control block

threat {
description = "Authentication is bypassed"
control "authentication_control" {
implemented = true
description = "Multi-factor authentication required"
implementation_notes = "Using TOTP for all admin accounts"
risk_reduction = 80
attribute "category" {
value = "Authentication"
}
attribute "framework" {
value = "NIST"
}
}
}

See External HCL Files for more information on how to refer to external files.

ref

The information_asset, threat and control blocks each accept an optional ref attribute: a reference to an item in a shared library, rather than a copy of it.

threat "SQL Injection" {
description = "Untrusted input reaches the database driver"
ref = "T-SQLI"
control "Parameterized Queries" {
description = "All queries use bound parameters"
ref = "C-PQUERY"
implemented = true
}
}

To threatcl itself a ref is just a string, and the file stays valid without a library to resolve it against. Threatcl Cloud uses these to link a model to its organization’s threat, control and information asset libraries. threatcl cloud view and threatcl cloud export resolve each ref and fill in the library’s description, STRIDE, implementation guidance, risk reduction and classification. Values you set locally always win over the library’s.

backend

A backend block sits at the top level of a file, outside your threatmodel blocks, and links the file to Threatcl Cloud.

backend "threatcl-cloud" {
organization = "acme"
threatmodel = "my-app"
}
AttributeTypeRequiredDescription
NAMElabel string The backend’s name, i.e. threatcl-cloud
organizationstring The organization this model belongs to
threatmodelstringThe cloud threat model slug
projectstringAn optional project

A file may declare at most one backend block.