Skip to content

Prompts

From docs/MCP_TOOLS.md on GitHub

Each prompt returns user messages only. The first holds the task and the exact tool calls to make. The task text never contains values from the workspace (dataset, asset, finding or framework names, account ids, the caller's own arguments): it points at the context instead, as in "the asset in the context (asset.id)". When data is loaded, the context follows so the model starts informed, in two forms: a text message Context for this task (JSON): with a fenced JSON block, and embedded resources whose URI serves exactly the embedded content (the dataset summary, an asset, a finding, a framework). Every context message also carries its data in _meta["cloudg/data"] with the rendering rule in _meta["cloudg/render"], so the privacy transforms work on the data with its keys and the text is rendered again from the transformed data. With no dataset loaded and no dataset argument, a prompt returns a single message explaining how to load data instead of failing (drift_review is the exception: it needs two datasets and raises):

description: "Security posture review"

Message 1 (user, text):

No cloudg dataset is loaded yet. First call `workspace_status`, then load data with `load_dataset(path=...)` (an inventory-map.json, findings.json or scanner report inside an allowed directory) or collect it with `map_inventory`. Then run this prompt again.

A dataset argument naming a dataset that is not loaded, a missing required argument, or an unknown asset or finding raises an error:

{
  "arguments": {},
  "error": "InvalidArgumentsError",
  "code": -32602,
  "message": "Missing required prompt arguments: ref"
}
{
  "arguments": {
    "ref": "web-9"
  },
  "error": "ReferenceNotFoundError",
  "code": -32602,
  "message": "No asset matches the reference in this dataset. 5 close matches, see suggestions in the error data. Use find_assets(query=...) to search by name, ARN or tag."
}
{
  "arguments": {
    "dataset": "nope"
  },
  "error": "NoDatasetError",
  "code": -32602,
  "message": "No such dataset. 3 dataset(s) are loaded: see datasets in the error data, or call list_datasets."
}

Asset, finding and framework resources always read the active dataset, so a prompt embeds them only when it targets the active dataset; for another dataset the same data goes into the JSON context message instead. drift_review embeds no resource, because no resource serves a diff.

Prompt Arguments Required Sensitivity JSON context Embedded resource Steers to
security_posture_review dataset none confidential The five riskiest assets, posture of the first five frameworks Dataset summary top_risks, internet_exposure, attack_paths, lateral_movement_paths, cross_account_edges, security_coverage, compliance_summary
executive_summary dataset none internal Overview figures Dataset summary findings_summary, compliance_summary, top_risks
attack_surface_report dataset none confidential Exposed count, exposed by type, first 15 exposed briefs Dataset summary internet_exposure, get_edges, attack_paths, find_paths, findings_for_asset
investigate_asset ref, dataset ref confidential dataset (plus the asset detail, when not the active dataset) cloudg://assets/{id} get_asset, get_asset_metadata, neighbors, depends_on, dependents, findings_for_asset, get_finding, blast_radius, find_paths, ontology_neighbourhood
blast_radius_assessment ref, dataset ref confidential Asset brief, transitive dependents (depth 10), accounts affected, first 20 direct dependents cloudg://assets/{id} blast_radius, dependency_tree, lateral_movement_paths, findings_for_asset
change_impact_analysis ref, change, dataset ref confidential Asset brief, up to 20 direct dependencies each way cloudg://assets/{id} dependents, dependency_tree, shared_dependencies, cross_account_edges, get_asset_metadata, snapshot_dataset, diff_datasets
cross_account_trust_review dataset none confidential Cross-account edge count, external count, counts per account pair and edge type Dataset summary cross_account_edges, get_edges, lateral_movement_paths, organization_topology
compliance_gap_analysis framework, dataset framework confidential dataset and framework (plus the framework detail, when not the active dataset; the posture alone when the framework does not resolve) cloudg://compliance/{framework} compliance_summary, list_controls, control_status, compliance_gaps
remediation_plan severity (default HIGH), dataset none confidential The ten riskiest assets at or above the severity Dataset summary list_findings, top_risks, get_finding, blast_radius, suppress_findings
incident_triage finding_id, dataset finding_id confidential dataset and target_ref, the affected asset (plus the finding detail, when not the active dataset) cloudg://findings/{id} get_finding, get_asset, internet_exposure, find_paths, blast_radius, lateral_movement_paths
drift_review base, target base confidential diff_datasets(base, target, limit=25) none diff_datasets, get_asset, findings_for_asset

Every JSON context also names the dataset (dataset), and change_impact_analysis adds the planned change as planned_change. All prompts carry the tag workflow in _meta. The messages below are real; the embedded JSON is trimmed like the other examples.

security_posture_review

description: "Security posture review"

Message 1 (user, text):

Review the security posture of the cloud estate in the dataset named in the
context. The embedded JSON has the overview, the five riskiest assets and compliance posture.

Work through, calling cloudg tools as needed:
1. `top_risks(top=10)`: the assets to fix first and why (score components).
2. `internet_exposure()` and `attack_paths()` for what an outside attacker can reach.
3. `lateral_movement_paths()` and `cross_account_edges(external_only=true)` (identity pivots).
4. `security_coverage()`: missing GuardDuty / Inspector / WAF etc.
5. `compliance_summary()` to find the weakest frameworks.

Deliver: an overall rating (critical / poor / fair / good) with justification, the top 5
risks with evidence (asset, finding, exposure, blast radius), quick wins, and structural
improvements. Cite asset names / ids exactly as tools return them.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "top_risks": [
    {
      "asset": "jump-nsg",
      "id": "az-nsg",
      "type": "NSG",
      "score": 16.39,
      "internet_exposed": false,
      "top_finding": "NSG allows RDP (3389) from Internet"
    },
    {
      "asset": "sg-admin",
      "id": "sg-admin",
      "type": "SECURITY_GROUP",
      "score": 16.39,
      "internet_exposed": false,
      "top_finding": "Security group allows SSH (22) from 0.0.0.0/0"
    },
    "... 3 more"
  ],
  "compliance": [
    {
      "framework": "CIS-AWS",
      "controls_evaluated": 4,
      "controls_failing": 3,
      "controls_passing": 1,
      "controls_other": 0,
      "pass_rate": 25.0,
      "open_findings": 6,
      "severity_breakdown": {
        "CRITICAL": 1,
        "HIGH": 3,
        "MEDIUM": 2
      },
      "affected_assets": 5,
      "uri": "cloudg://compliance/CIS-AWS"
    },
    {
      "framework": "PCI-DSS",
      "controls_evaluated": 1,
      "controls_failing": 1,
      "controls_passing": 0,
      "controls_other": 0,
      "pass_rate": 0.0,
      "open_findings": 3,
      "severity_breakdown": {
        "CRITICAL": 1,
        "HIGH": 2
      },
      "affected_assets": 3,
      "uri": "cloudg://compliance/PCI-DSS"
    },
    "... 3 more"
  ]
}

Message 3 (user, embedded resource cloudg://datasets/sample/summary, application/json): the dataset_summary object of sample.

executive_summary

description: "Executive summary"

Message 1 (user, text):

Write a one-page executive summary of the cloud security state of the dataset
in the context for non-technical leadership, from the embedded figures (call
`findings_summary`, `compliance_summary` and `top_risks(top=3)` for anything missing).

Structure: headline (one sentence), scale of the estate, risk level with the 3 issues that
matter most in business terms, compliance standing, and 3 recommended decisions with rough
effort. No identifiers or jargon; numbers rounded.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "providers": [
    "aws",
    "azure",
    "gcp"
  ],
  "total_assets": 44,
  "total_edges": 56,
  "open_findings": 11,
  "severity_breakdown": {
    "CRITICAL": 2,
    "HIGH": 5,
    "MEDIUM": 2,
    "LOW": 1,
    "INFO": 1
  },
  "accounts": 5,
  "regions": 5,
  "internet_exposed": 6,
  "cross_account_edges": 3,
  "compliance_frameworks": [
    "CIS-AWS",
    "CIS-Azure",
    "CIS-GCP",
    "... 2 more"
  ],
  "assets_by_type": {
    "SECURITY_GROUP": 4,
    "IAM_ROLE": 4,
    "CLOUD_ACCOUNT": 3,
    "EC2": 3,
    "S3_BUCKET": 3,
    "...": "10 more"
  }
}

Message 3 (user, embedded resource cloudg://datasets/sample/summary, application/json): the dataset_summary object of sample.

attack_surface_report

description: "Attack surface report"

Message 1 (user, text):

Map the external attack surface of the dataset named in the context.

1. `internet_exposure(limit=100)`: every exposed asset with the rules exposing it, sensitive
   ports and WAF protection.
2. `get_edges(internet_only=true, port=22)` and `port=3389` for admin ports open to the world.
3. `attack_paths(max_paths=20)`: routes from the internet to data stores, secrets, keys, roles.
4. For the worst 3 paths, `find_paths(source='internet', target=<asset>)` and
   `findings_for_asset` on each hop.

Report: entry points ranked by risk, exposed sensitive services, the critical paths with
every hop explained, and concrete fixes (close rule X, add WAF to Y, move Z private).

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "internet_exposed_total": 6,
  "exposed_by_type": {
    "LOAD_BALANCER": 1,
    "EC2": 1,
    "S3_BUCKET": 1,
    "API_GATEWAY": 1,
    "VIRTUAL_MACHINE": 1,
    "GCS_BUCKET": 1
  },
  "exposed_sample": [
    {
      "id": "alb-web",
      "name": "web-alb",
      "type": "LOAD_BALANCER",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:elasticloadbalancing:us-east-1:111111111111:loadbalancer/app/web-alb/abc",
      "internet_exposed": true,
      "open_findings": 0,
      "max_severity": null,
      "uri": "cloudg://assets/alb-web"
    },
    {
      "id": "bastion",
      "name": "bastion",
      "type": "EC2",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:ec2:us-east-1:111111111111:instance/i-0bast",
      "internet_exposed": true,
      "open_findings": 1,
      "max_severity": "HIGH",
      "uri": "cloudg://assets/bastion"
    },
    "... 4 more"
  ]
}

Message 3 (user, embedded resource cloudg://datasets/sample/summary, application/json): the dataset_summary object of sample.

investigate_asset

description: "Investigate asset"

Message 1 (user, text):

Investigate the asset described in the context (use its `id` as `ref` in the
calls below). Its current detail is embedded.

1. `get_asset(ref=<id>)` and `get_asset_metadata` (specific keys) for configuration.
2. `neighbors(ref, depth=2)` for what it connects to, then `depends_on` / `dependents`.
3. `findings_for_asset(ref)` then `get_finding` on the serious ones.
4. `blast_radius(ref)` and, if it is exposed, `find_paths(source='internet', target=ref)`.
5. `ontology_neighbourhood(ref)` for semantic relations (encryption, protection, ownership).

Report what it is, who owns it (tags), how it is exposed, what it can reach, what depends on
it, its findings, and prioritised recommendations.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample"
}

Message 3 (user, embedded resource cloudg://assets/orders-db, application/json):

{
  "id": "orders-db",
  "name": "orders-db",
  "type": "RDS_INSTANCE",
  "provider": "AWS",
  "region": "us-east-1",
  "account_id": "111111111111",
  "arn": "arn:aws:rds:us-east-1:111111111111:db:orders-db",
  "internet_exposed": false,
  "open_findings": 1,
  "max_severity": "MEDIUM",
  "uri": "cloudg://assets/orders-db",
  "tags": {
    "env": "prod",
    "data": "pii"
  },
  "relations": {
    "outgoing": {
      "ATTACHED_TO": 1,
      "REFERENCES": 1
    },
    "incoming": {
      "CONTAINS": 1,
      "GRANTS_ACCESS": 1
    }
  },
  "findings": [
    {
      "id": "f-db-backup",
      "title": "RDS backup retention below 7 days",
      "severity": "MEDIUM",
      "risk_score": 5.0,
      "source_tool": "prowler",
      "resource_id": "arn:aws:rds:us-east-1:111111111111:db:orders-db",
      "resource_arn": null,
      "asset_id": "orders-db",
      "asset_name": "orders-db",
      "compliance_frameworks": [
        "CIS-AWS",
        "NIST-800-53"
      ],
      "is_suppressed": false,
      "cvss_score": null,
      "detected_at": "2026-01-15T12:00:00+00:00",
      "uri": "cloudg://findings/f-db-backup"
    }
  ],
  "metadata_keys": [
    "backup_retention",
    "engine"
  ],
  "dependencies": {
    "direct_depends_on": 3,
    "direct_dependents": 1
  }
}

blast_radius_assessment

description: "Blast radius assessment"

Message 1 (user, text):

Assess the blast radius of the asset in the context (`asset.id`) if it is
(a) compromised and (b) deleted or unavailable.

1. `blast_radius(ref=<asset.id>)`: dependency and network reach, sensitive stores reachable.
2. `dependency_tree(ref, direction='down')` shows what breaks, layer by layer.
3. `lateral_movement_paths(start=<asset.id>)` for identity pivots from it.
4. `findings_for_asset` on the most critical dependents.

Report both scenarios with affected services / accounts / data, severity, and containment
and resilience recommendations (least privilege, redundancy, segmentation).

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "asset": {
    "id": "kms-main",
    "name": "prod-main-key",
    "type": "KMS_KEY",
    "provider": "AWS",
    "region": "us-east-1",
    "account_id": "111111111111",
    "arn": "arn:aws:kms:us-east-1:111111111111:key/1111-2222",
    "internet_exposed": false,
    "open_findings": 0,
    "max_severity": null,
    "uri": "cloudg://assets/kms-main"
  },
  "transitive_dependents": 12,
  "accounts_affected": [
    "111111111111"
  ],
  "direct_dependents": [
    {
      "id": "api-handler",
      "name": "api-handler",
      "type": "LAMBDA_FUNCTION",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:lambda:us-east-1:111111111111:function:api-handler",
      "internet_exposed": false,
      "open_findings": 1,
      "max_severity": "LOW",
      "uri": "cloudg://assets/api-handler"
    },
    {
      "id": "data-bucket",
      "name": "prod-data",
      "type": "S3_BUCKET",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:s3:::prod-data",
      "internet_exposed": false,
      "open_findings": 0,
      "max_severity": null,
      "uri": "cloudg://assets/data-bucket"
    },
    "... 2 more"
  ]
}

Message 3 (user, embedded resource cloudg://assets/kms-main, application/json):

{
  "id": "kms-main",
  "name": "prod-main-key",
  "type": "KMS_KEY",
  "provider": "AWS",
  "region": "us-east-1",
  "account_id": "111111111111",
  "arn": "arn:aws:kms:us-east-1:111111111111:key/1111-2222",
  "internet_exposed": false,
  "open_findings": 0,
  "max_severity": null,
  "uri": "cloudg://assets/kms-main",
  "tags": {},
  "relations": {
    "outgoing": {},
    "incoming": {
      "REFERENCES": 4
    }
  },
  "findings": [],
  "metadata_keys": [],
  "dependencies": {
    "direct_depends_on": 0,
    "direct_dependents": 4
  }
}

change_impact_analysis

description: "Change impact analysis"

Message 1 (user, text):

Plan the change described in the context (`planned_change`) to the asset in the
context (`asset.id`). Direct upstream / downstream dependencies are embedded.

1. `dependents(ref=<asset.id>, max_depth=5)` and `dependency_tree(ref, direction='down')`.
2. `shared_dependencies()`: is it a single point of failure?
3. `cross_account_edges(account_id=<asset.account_id>)` for other accounts affected.
4. `get_asset_metadata(ref)` for the settings being changed.

Deliver: affected components ranked by impact, risks, pre-checks, a rollout and rollback
plan, and how to verify (e.g. snapshot_dataset now, re-collect after, diff_datasets).

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "planned_change": "remove port 5432 ingress",
  "asset": {
    "id": "sg-app",
    "name": "sg-app",
    "type": "SECURITY_GROUP",
    "provider": "AWS",
    "region": "us-east-1",
    "account_id": "111111111111",
    "arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0app",
    "internet_exposed": false,
    "open_findings": 0,
    "max_severity": null,
    "uri": "cloudg://assets/sg-app"
  },
  "depends_on": [],
  "dependents": [
    {
      "id": "web-1",
      "name": "web-1",
      "type": "EC2",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web1",
      "internet_exposed": false,
      "open_findings": 1,
      "max_severity": "HIGH",
      "uri": "cloudg://assets/web-1"
    },
    {
      "id": "web-2",
      "name": "web-2",
      "type": "EC2",
      "provider": "AWS",
      "region": "us-east-1",
      "account_id": "111111111111",
      "arn": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web2",
      "internet_exposed": false,
      "open_findings": 0,
      "max_severity": null,
      "uri": "cloudg://assets/web-2"
    }
  ]
}

Message 3 (user, embedded resource cloudg://assets/sg-app, application/json):

{
  "id": "sg-app",
  "name": "sg-app",
  "type": "SECURITY_GROUP",
  "provider": "AWS",
  "region": "us-east-1",
  "account_id": "111111111111",
  "arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0app",
  "internet_exposed": false,
  "open_findings": 0,
  "max_severity": null,
  "uri": "cloudg://assets/sg-app",
  "tags": {},
  "relations": {
    "outgoing": {
      "SECURITY_GROUP_RULE": 1
    },
    "incoming": {
      "ATTACHED_TO": 2
    }
  },
  "findings": [],
  "metadata_keys": [],
  "dependencies": {
    "direct_depends_on": 0,
    "direct_dependents": 2
  }
}

cross_account_trust_review

description: "Cross-account trust review"

Message 1 (user, text):

Review trust relationships across account boundaries in the dataset named in the
context.

1. `cross_account_edges(external_only=true)` then all of them by account pair.
2. `get_edges(edge_types=['IAM_TRUST'])` and `get_edges(edge_types=['GRANTS_ACCESS'],
   cross_account_only=true)`.
3. `lateral_movement_paths()`: chains a compromised external principal could follow.
4. `organization_topology(include_policies=true)` for SCPs that limit the blast radius.

Flag unknown / external accounts, overly broad trust (account root, wildcards), missing
external-id conditions, and recommend tightening with evidence for each.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "cross_account_edges": 3,
  "external": 1,
  "by_account_pair": {
    "111111111111 -> 222222222222 (IAM_TRUST)": 1,
    "999999999999 -> 222222222222 (IAM_TRUST)": 1,
    "111111111111 -> 222222222222 (USES_IMAGE)": 1
  }
}

Message 3 (user, embedded resource cloudg://datasets/sample/summary, application/json): the dataset_summary object of sample.

compliance_gap_analysis

description: "Compliance gap analysis"

Message 1 (user, text):

Run a compliance gap analysis for the framework named in the context
(`framework`, called <framework> below).

1. `compliance_summary(framework=<framework>)`.
2. `list_controls(framework=<framework>, status='FAIL')` and
   `list_controls(framework=<framework>, source='ruleset')` for the full control set.
3. `control_status` on the failing controls with the most / worst findings.
4. `compliance_gaps(framework=<framework>)` to list the assets behind the gaps.

Deliver: pass rate and failing controls grouped by domain, the assets responsible, a
remediation backlog ordered by severity x effort, and evidence references (finding ids).

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "framework": "PCI-DSS"
}

Message 3 (user, embedded resource cloudg://compliance/PCI-DSS, application/json):

{
  "dataset": "sample",
  "posture": [
    {
      "framework": "PCI-DSS",
      "controls_evaluated": 1,
      "controls_failing": 1,
      "controls_passing": 0,
      "controls_other": 0,
      "pass_rate": 0.0,
      "open_findings": 3,
      "severity_breakdown": {
        "CRITICAL": 1,
        "HIGH": 2
      },
      "affected_assets": 3,
      "uri": "cloudg://compliance/PCI-DSS"
    }
  ],
  "failing_controls": [
    {
      "framework": "PCI-DSS",
      "control_id": "1.3.1",
      "control_title": "Inbound traffic restricted",
      "open_findings": 2,
      "max_severity": "CRITICAL"
    }
  ]
}

remediation_plan

severity is upper-cased and defaults to HIGH; it is not checked until top_risks runs inside the prompt, so a bad value raises the usual severity error.

description: "Remediation plan"

Message 1 (user, text):

Build a remediation plan for open findings at CRITICAL or above in the dataset named
in the context.

1. `list_findings(min_severity='CRITICAL', limit=100)` (page with next_cursor if needed).
2. `top_risks(top=20, min_severity='CRITICAL')` to order work by real risk.
3. `get_finding` for remediation text; `blast_radius` on assets where a fix may disrupt.
4. Group fixes that share a root cause (same security group, role, policy, account setting).

Deliver: phased plan (now / this sprint / next quarter) with owner hints from tags, each
item with finding ids, affected assets, the fix, its risk reduction and change risk. Note
accepted risks that could be suppressed (suppress_findings) with the reason.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "min_severity": "CRITICAL",
  "top_risks": [
    {
      "asset": "jump-nsg",
      "id": "az-nsg",
      "type": "NSG",
      "score": 16.39,
      "internet_exposed": false,
      "top_finding": "NSG allows RDP (3389) from Internet"
    },
    {
      "asset": "sg-admin",
      "id": "sg-admin",
      "type": "SECURITY_GROUP",
      "score": 16.39,
      "internet_exposed": false,
      "top_finding": "Security group allows SSH (22) from 0.0.0.0/0"
    }
  ]
}

Message 3 (user, embedded resource cloudg://datasets/sample/summary, application/json): the dataset_summary object of sample.

incident_triage

description: "Incident triage"

Message 1 (user, text):

Triage the finding in the context (CRITICAL) as a potential
incident. `id` is the finding id and `target_ref` the affected asset (<target> below).

1. `get_finding(finding_id=<id>)` for evidence and mapped controls.
2. `get_asset(ref=<target>)` and `internet_exposure()`: is the affected asset reachable?
3. `find_paths(source='internet', target=<target>)` and `blast_radius(ref=<target>)`.
4. `lateral_movement_paths(start=<target>)` to see where an attacker goes next.

Deliver: is it exploitable (likely / possible / unlikely) and why, impact if exploited,
immediate containment steps, evidence to collect, the permanent fix, and severity
re-rating if justified.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "dataset": "sample",
  "target_ref": "sg-admin"
}

Message 3 (user, embedded resource cloudg://findings/f-ssh-open, application/json):

{
  "id": "f-ssh-open",
  "title": "Security group allows SSH (22) from 0.0.0.0/0",
  "severity": "CRITICAL",
  "risk_score": 9.5,
  "source_tool": "prowler",
  "resource_id": "sg-admin",
  "resource_arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
  "asset_id": "sg-admin",
  "asset_name": "sg-admin",
  "compliance_frameworks": [
    "CIS-AWS",
    "PCI-DSS"
  ],
  "is_suppressed": false,
  "cvss_score": null,
  "detected_at": "2026-01-15T12:00:00+00:00",
  "uri": "cloudg://findings/f-ssh-open",
  "description": "Security group allows SSH (22) from 0.0.0.0/0.",
  "evidence": "IpPermissions 0.0.0.0/0 tcp 22",
  "remediation": "Restrict 22 to the VPN."
}

drift_review

There is no dataset argument; target empty means the active dataset.

description: "Drift review"

Message 1 (user, text):

Review what changed between the datasets `base` (before) and `target` (after)
named in the context. The diff is embedded (counts plus the first items).

Call `diff_datasets(base=<base>, target=<target>, limit=200)` for more, and `get_asset` /
`findings_for_asset` on anything suspicious. Report: new or newly exposed assets, removed
controls (security groups, WAF, logging), new trust edges, findings introduced vs resolved,
and whether each change looks intended or like drift.

Message 2 (user, text): Context for this task (JSON): followed by a fenced JSON block:

{
  "base": "baseline",
  "target": "after",
  "assets": {
    "added": {
      "count": 0,
      "items": [],
      "truncated": false
    },
    "removed": {
      "count": 1,
      "items": [
        {
          "id": "waf-web",
          "key": "arn:aws:wafv2:us-east-1:111111111111:regional/webacl/web-acl/1",
          "name": "web-acl",
          "type": "WAF_WEB_ACL",
          "account_id": "111111111111",
          "region": "us-east-1"
        }
      ],
      "truncated": false
    },
    "changed": {
      "count": 1,
      "items": [
        {
          "id": "web-2",
          "key": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web2",
          "name": "web-2",
          "type": "EC2",
          "account_id": "111111111111",
          "region": "us-east-1",
          "changed_fields": [
            "internet_exposed",
            "tags"
          ],
          "internet_exposed": {
            "before": false,
            "after": true
          }
        }
      ],
      "truncated": false
    },
    "unchanged": 42
  },
  "edges": {
    "added": {
      "count": 1,
      "items": [
        {
          "source": "0.0.0.0/0",
          "target": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web2",
          "edge_type": "INTERNET_EXPOSED",
          "relationship": "INTERNET_REACHABLE"
        }
      ],
      "truncated": false
    },
    "removed": {
      "count": 1,
      "items": [
        {
          "source": "arn:aws:wafv2:us-east-1:111111111111:regional/webacl/web-acl/1",
          "target": "arn:aws:elasticloadbalancing:us-east-1:111111111111:loadbalancer/app/web-alb/abc",
          "edge_type": "PROTECTS",
          "relationship": null
        }
      ],
      "truncated": false
    }
  },
  "findings": {
    "new": {
      "count": 0,
      "items": [],
      "truncated": false
    },
    "resolved": {
      "count": 1,
      "items": [
        {
          "id": "f-ssh-open",
          "title": "Security group allows SSH (22) from 0.0.0.0/0",
          "severity": "CRITICAL",
          "resource": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
          "source_tool": "prowler"
        }
      ],
      "truncated": false
    },
    "severity_changed": {
      "count": 1,
      "items": [
        {
          "id": "f-db-backup",
          "title": "RDS backup retention below 7 days",
          "severity": "HIGH",
          "resource": "arn:aws:rds:us-east-1:111111111111:db:orders-db",
          "source_tool": "prowler",
          "severity_before": "MEDIUM"
        }
      ],
      "truncated": false
    }
  },
  "newly_internet_exposed": {
    "count": 1,
    "items": [
      {
        "id": "web-2",
        "key": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web2",
        "name": "web-2",
        "type": "EC2",
        "account_id": "111111111111",
        "region": "us-east-1",
        "changed_fields": [
          "internet_exposed",
          "tags"
        ],
        "internet_exposed": {
          "before": false,
          "after": true
        }
      }
    ],
    "truncated": false
  }
}