Skip to main content

Static IaC threat modeler using STRIDE, MITRE, and PASTA

Project description

image

threatmap

CI Python License: MIT Offline

Static IaC threat modeler that parses Terraform, CloudFormation, and Kubernetes manifests and produces structured threat model reports using STRIDE, MITRE ATT&CK, or PASTA frameworks. No network calls, no cloud credentials, fully offline. Runs as a CLI, REST API, or containerized service.


Quick Start

CLI:

pip install threatmap
threatmap scan ./examples --output report.md --fail-on HIGH

Docker:

docker run -v $(pwd):/workspace threatmap:2.0.0 threatmap scan /workspace --output /workspace/report.md

API Server:

threatmap serve --host 0.0.0.0 --port 8000
# Or via Docker:
docker run -p 8000:8000 threatmap:2.0.0
# Then POST to http://localhost:8000/analyze with IaC content

Supported Formats and Providers

Format Provider Extension
Terraform HCL AWS, Azure, GCP .tf
CloudFormation AWS .yaml, .yml, .json
Kubernetes manifests Kubernetes .yaml, .yml

Install

Install from PyPI:

pip install threatmap

Or for local development:

git clone https://github.com/bogdanticu88/threatmap.git
cd threatmap
pip install -e .

Usage

Scan a directory and print a Markdown report to stdout:

threatmap scan ./terraform/

Scan multiple paths and write a JSON report to a file:

threatmap scan ./terraform/ ./k8s/ ./cloudformation/ --format json --output report.json

Generate an interactive HTML report or a SARIF report for GitHub Security:

threatmap scan ./infra/ --format html --output report.html
threatmap scan ./infra/ --format sarif --output report.sarif

CI gate โ€” exit code 1 if any CRITICAL or HIGH threat is found:

threatmap scan ./infra/ --fail-on HIGH --output threat-report.md

Print a terminal summary table only, without writing a full report:

threatmap scan ./infra/ --summary

Use ASCII-only severity indicators (no emojis) for environments that don't support Unicode:

threatmap scan ./infra/ --ascii --output report.md

Analyze using different threat modeling frameworks:

# STRIDE (default)
threatmap scan ./infra/ --framework stride

# MITRE ATT&CK (maps to tactics and techniques)
threatmap scan ./infra/ --framework mitre --format json

# PASTA (asset-centric threat modeling)
threatmap scan ./infra/ --framework pasta --format json

Threat Modeling Frameworks

STRIDE (default)

  • Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege
  • Threat-centric approach ideal for identifying attack surface
  • Best for: Traditional threat modeling, security architecture reviews

MITRE ATT&CK

  • Maps infrastructure threats to real-world adversary tactics and techniques
  • Includes 14 tactics (Reconnaissance, Initial Access, Persistence, etc.)
  • Best for: Aligning with threat intelligence, incident response planning

PASTA

  • Process for Attack Simulation and Threat Analysis
  • Asset-centric approach focusing on what needs protection
  • Classifies assets by type (data, identity, compute, network)
  • Best for: Risk-based prioritization, asset protection strategies

Sample Report Output

Running threatmap scan ./examples --output report.md against the bundled examples produces a full Markdown report. Below is a representative excerpt.

STRIDE Threat Table

ID Severity STRIDE Category Resource Description
T-001 ๐Ÿ”ด CRITICAL Information Disclosure AuditBucket S3 bucket 'AuditBucket' has no public access block configured โ€” bucket may be publicly accessible.
T-002 ๐Ÿ”ด CRITICAL Spoofing WebSecurityGroup Security group 'WebSecurityGroup' exposes SSH/RDP (port 22/3389) to 0.0.0.0/0.
T-003 ๐Ÿ”ด CRITICAL Elevation of Privilege app_contributor Role assignment 'app_contributor' grants the privileged role 'Contributor'.
T-006 ๐ŸŸ  HIGH Information Disclosure AuditBucket S3 bucket 'AuditBucket' does not have server-side encryption configured.
T-008 ๐ŸŸ  HIGH Elevation of Privilege api Container 'api' in Deployment 'api' may run as root (no runAsNonRoot=true or runAsUser=0).
T-011 ๐ŸŸ  HIGH Elevation of Privilege web EC2 instance 'web' allows IMDSv1 โ€” metadata service accessible without session tokens, enabling SSRF-based credential theft.

Mitigation Detail (excerpt)

### T-002 โ€” Spoofing (CRITICAL)

Resource:   AWS::EC2::SecurityGroup.WebSecurityGroup
Property:   ingress.ssh_rdp_open
Finding:    Security group 'WebSecurityGroup' exposes SSH/RDP (port 22/3389) to 0.0.0.0/0.
Mitigation: Remove public SSH/RDP access. Use AWS Systems Manager Session Manager
            or a bastion host with IP restrictions.

Data Flow Diagram (Mermaid)

The report appends a Mermaid flowchart LR diagram. Nodes are coloured by worst-case severity (๐Ÿ”ด red = CRITICAL, ๐ŸŸ  orange = HIGH). Paste the block into any Mermaid renderer or view it directly on GitHub.

flowchart LR
    Internet((Internet))
    subgraph Networking
        aws_security_group_web_sg{web_sg}
        NetworkPolicy_default_deny{default-deny}
        azurerm_network_security_group_app_nsg{app_nsg}
    end
    subgraph Compute
        aws_instance_web[web]
    end
    subgraph Kubernetes
        Namespace_myapp[myapp]
        Deployment_api[api]
        Service_api_svc[api-svc]
        Ingress_api_ingress[api-ingress]
    end
    subgraph Data
        aws_s3_bucket_app_data[(app_data)]
        aws_db_instance_app_db[(app_db)]
        azurerm_storage_account_app_storage[(app_storage)]
    end
    subgraph Security
        azurerm_key_vault_app_kv[app_kv]
    end
    subgraph Identity
        azurerm_role_assignment_app_contributor[/app_contributor/]
    end
    AWS__S3__Bucket_AppBucket -->|ref| AWS__S3__Bucket_AuditBucket
    AWS__CloudTrail__Trail_AppTrail -->|ref| AWS__S3__Bucket_AuditBucket
    Internet -->|HTTPS| Ingress_api_ingress
    style aws_security_group_web_sg fill:#ff4444,color:#fff
    style aws_s3_bucket_app_data fill:#ff4444,color:#fff
    style aws_instance_web fill:#ff8800,color:#fff
    style Deployment_api fill:#ff8800,color:#fff
    style azurerm_key_vault_app_kv fill:#ffcc00,color:#000
    style azurerm_network_security_group_app_nsg fill:#ff8800,color:#fff
    style azurerm_role_assignment_app_contributor fill:#ff4444,color:#fff

Advanced Features (v1.1.0+)

Graph-based Attack Path Analysis

threatmap now includes Graph Intelligence that traces relationships between resources. It automatically identifies "chained" threats where a compromise of one resource (e.g., an internet-exposed EC2) leads directly to another (e.g., a private S3 bucket), flagging these as Elevation of Privilege attack paths.

Custom YAML Rules

You can define internal security requirements by creating a threatmap_rules.yaml in your project root.

rules:
  - resource_type: "aws_s3_bucket"
    property: "force_destroy"
    expected: false
    stride: "Tampering"
    severity: "MEDIUM"
    description: "Production buckets should not have force_destroy enabled."
    mitigation: "Set force_destroy = false."

Remediation Hints

Most findings now include a remediation field (visible in JSON, HTML, and SARIF reports) that provides the exact code snippet needed to fix the security issue.


Where rules live

Each cloud provider has its own analyzer module:

threatmap/analyzers/
โ”œโ”€โ”€ aws.py         # 22 rules โ€” S3, IAM, EC2, RDS, EKS, CloudTrail, KMS, Lambda
โ”œโ”€โ”€ azure.py       # 19 rules โ€” Storage, Key Vault, NSG, RBAC, AKS, ACR, SQL
โ”œโ”€โ”€ gcp.py         # 15 rules โ€” GCS, Firewall, Compute, Cloud SQL, GKE, IAM, KMS
โ””โ”€โ”€ kubernetes.py  # 17 rules โ€” workloads, RBAC, network, secrets

Each rule is a function that receives a Resource object (normalised from whatever source format was parsed) and returns a Threat if the condition is met. Rules are plain Python conditionals โ€” no DSL, no regex engine, no external ruleset files.

How severities are assigned

Severity reflects both exploitability and blast radius:

Severity Meaning
CRITICAL Directly exploitable with no additional preconditions (e.g. SSH open to 0.0.0.0/0, wildcard IAM policy, cluster-admin binding to anonymous)
HIGH Significant risk requiring one additional step (e.g. unencrypted RDS with public access, IMDSv1 on an EC2 instance)
MEDIUM Defence-in-depth controls missing โ€” lower immediate risk but violates security baselines (e.g. no versioning, no logging, no resource limits)
LOW Best-practice gaps with limited standalone exploitability (e.g. Lambda not in VPC)

How false positives are avoided

  • No heuristics or ML โ€” every rule fires on a concrete, unambiguous property value (e.g. publicly_accessible = true, Principal: "*").
  • Conservative defaults โ€” if a property is absent, the rule assumes the insecure default (e.g. no metadata_options block on an EC2 instance means IMDSv1 is active, because that is AWS's default).
  • No cross-account or runtime state โ€” the tool only looks at what is declared in the template. It does not attempt to infer what SCPs, permission boundaries, or runtime configs might mitigate a finding.
  • Deduplication in the engine โ€” findings are keyed on (stride_category, resource_name, trigger_property) so the same logical issue is never reported twice even if it appears across multiple file formats.

CI Integration

# .github/workflows/threat-model.yml
name: Threat Model

on: [pull_request]

jobs:
  threatmap:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install threatmap
        run: pip install threatmap

      - name: Run threat model scan
        run: |
          threatmap scan ./infra/ \
            --format markdown \
            --output threat-report.md \
            --fail-on HIGH

      - name: Upload threat report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: threat-report
          path: threat-report.md

The --fail-on HIGH flag makes the job exit with code 1 if any HIGH or CRITICAL threat is found, blocking the PR merge. The uploaded artifact gives reviewers the full report without leaving the pull request.


STRIDE Rule Coverage

Provider Rules
AWS (Terraform + CloudFormation) 22
Azure (Terraform) 19
GCP (Terraform) 15
Kubernetes 17
Total 73

Categories covered per provider:

Provider S T R I D E
AWS โœ“ โœ“ โœ“ โœ“ โœ“ โœ“
Azure โœ“ โœ“ โœ“ โœ“ โ€” โœ“
GCP โœ“ โœ“ โœ“ โœ“ โ€” โœ“
Kubernetes โœ“ โœ“ โ€” โœ“ โœ“ โœ“

(S=Spoofing, T=Tampering, R=Repudiation, I=Information Disclosure, D=Denial of Service, E=Elevation of Privilege)


Development

Run tests:

pytest tests/ -v

Run with coverage:

pytest tests/ --cov=threatmap --cov-report=term-missing

Contributing

  1. Fork the repository
  2. Add rules in threatmap/analyzers/<provider>.py following the existing pattern
  3. Add a fixture in tests/fixtures/ that triggers the new rule
  4. Add assertions in tests/test_analyzers.py
  5. Open a pull request

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

threatmap-2.1.0.tar.gz (57.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

threatmap-2.1.0-py3-none-any.whl (59.3 kB view details)

Uploaded Python 3

File details

Details for the file threatmap-2.1.0.tar.gz.

File metadata

  • Download URL: threatmap-2.1.0.tar.gz
  • Upload date:
  • Size: 57.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for threatmap-2.1.0.tar.gz
Algorithm Hash digest
SHA256 e70e5b4a9ac2eb0cf2568b51914a921f7ccee3f9e0533036c305ccc35c4c41d7
MD5 769ae6c950cae6bb102b4f30d4d9f07c
BLAKE2b-256 921ef6a32f64ac494a27d042b2759ff1bd3623a5916f61b609af38e573bbd471

See more details on using hashes here.

File details

Details for the file threatmap-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: threatmap-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 59.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for threatmap-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b0ecc12b1f004ffbf58eb289bb0b02ef13e2fd0deb9696fda60a740520769c76
MD5 22c0d0005b94d50a72df1774c8335655
BLAKE2b-256 da3cef2c350547d5b3198daba2600e743f9e561b1b08564164318bfc697ec514

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page