diff --git a/docs/attack-techniques/GCP/gcp.impact.invoke-vertex-ai-model.md b/docs/attack-techniques/GCP/gcp.impact.invoke-vertex-ai-model.md
new file mode 100755
index 000000000..088676c38
--- /dev/null
+++ b/docs/attack-techniques/GCP/gcp.impact.invoke-vertex-ai-model.md
@@ -0,0 +1,57 @@
+---
+title: Invoke a Vertex AI Model
+---
+
+# Invoke a Vertex AI Model
+
+
+ idempotent
+
+Platform: GCP
+
+## Mappings
+
+- MITRE ATT&CK
+ - Impact
+
+
+
+## Description
+
+
+Invokes a Gemini generative AI model via the Vertex AI API. This simulates
+an attacker who has obtained access to a GCP service account and abuses it
+to run large language model workloads, incurring unexpected costs for the
+victim organization.
+
+Prerequisites:
+
+- AI Platform API enabled (gcloud services enable aiplatform.googleapis.com)
+
+Detonation:
+
+- Call the Vertex AI API to generate content using a Gemini model
+ in the us-central1 region
+
+References:
+
+- https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference
+- https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.endpoints/generateContent
+- https://sysdig.com/blog/llmjacking-stolen-cloud-credentials-used-in-new-ai-attack/
+- https://unit42.paloaltonetworks.com/privilege-escalation-llm-model-exfil-vertex-ai/
+
+
+## Instructions
+
+```bash title="Detonate with Stratus Red Team"
+stratus detonate gcp.impact.invoke-vertex-ai-model
+```
+## Detection
+
+
+Identify unexpected Vertex AI model invocations by monitoring for
+google.cloud.aiplatform.v1.PredictionService.GenerateContent events in
+GCP Data Access audit logs, particularly from unexpected service accounts or at
+unusual times/volumes.
+
+
diff --git a/docs/attack-techniques/GCP/index.md b/docs/attack-techniques/GCP/index.md
index 049274801..18d1840c9 100755
--- a/docs/attack-techniques/GCP/index.md
+++ b/docs/attack-techniques/GCP/index.md
@@ -99,3 +99,5 @@ Note that some Stratus attack techniques may correspond to more than a single AT
- [Create GCE Instances in Multiple Zones](./gcp.impact.create-instances-in-multiple-zones.md)
+ - [Invoke a Vertex AI Model](./gcp.impact.invoke-vertex-ai-model.md)
+
diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md
index 31780c8d5..6f85e31a7 100755
--- a/docs/attack-techniques/list.md
+++ b/docs/attack-techniques/list.md
@@ -86,6 +86,7 @@ This page contains the list of all Stratus Attack Techniques.
| [Exfiltrate Compute Disk by sharing a snapshot](./GCP/gcp.exfiltration.share-compute-snapshot.md) | [GCP](./GCP/index.md) | Exfiltration |
| [Create a GCE GPU Virtual Machine](./GCP/gcp.impact.create-gpu-vm.md) | [GCP](./GCP/index.md) | Impact |
| [Create GCE Instances in Multiple Zones](./GCP/gcp.impact.create-instances-in-multiple-zones.md) | [GCP](./GCP/index.md) | Impact |
+| [Invoke a Vertex AI Model](./GCP/gcp.impact.invoke-vertex-ai-model.md) | [GCP](./GCP/index.md) | Impact |
| [Steal and Use the GCE Default Service Account Token from Outside Google Cloud](./GCP/gcp.initial-access.use-compute-sa-outside-gcp.md) | [GCP](./GCP/index.md) | Credential Access, Initial Access |
| [Register SSH public key to instance metadata](./GCP/gcp.lateral-movement.add-sshkey-instance-metadata.md) | [GCP](./GCP/index.md) | Lateral Movement, Persistence |
| [Backdoor a GCP Service Account through its IAM Policy](./GCP/gcp.persistence.backdoor-service-account-policy.md) | [GCP](./GCP/index.md) | Persistence |
diff --git a/docs/attack-techniques/mitre-attack-coverage-matrices.md b/docs/attack-techniques/mitre-attack-coverage-matrices.md
index f63941556..90649bfc3 100644
--- a/docs/attack-techniques/mitre-attack-coverage-matrices.md
+++ b/docs/attack-techniques/mitre-attack-coverage-matrices.md
@@ -57,7 +57,7 @@ This provides coverage matrices of MITRE ATT&CK tactics and techniques currently
us-central1 region
+
+References:
+
+- https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference
+- https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.endpoints/generateContent
+- https://sysdig.com/blog/llmjacking-stolen-cloud-credentials-used-in-new-ai-attack/
+- https://unit42.paloaltonetworks.com/privilege-escalation-llm-model-exfil-vertex-ai/
+`,
+ Detection: `
+Identify unexpected Vertex AI model invocations by monitoring for
+google.cloud.aiplatform.v1.PredictionService.GenerateContent events in
+GCP Data Access audit logs, particularly from unexpected service accounts or at
+unusual times/volumes.
+`,
+ Platform: stratus.GCP,
+ IsIdempotent: true,
+ MitreAttackTactics: []mitreattack.Tactic{mitreattack.Impact},
+ Detonate: detonate,
+ })
+}
+
+func detonate(_ map[string]string, providers stratus.CloudProviders) error {
+ gcp := providers.GCP()
+ projectId := gcp.GetProjectId()
+ ctx := context.Background()
+
+ client, err := genai.NewClient(ctx, projectId, "us-central1", gcp.Options())
+ if err != nil {
+ return fmt.Errorf("failed to create Vertex AI client: %w", err)
+ }
+ defer client.Close()
+
+ for _, modelName := range candidateModels {
+ log.Printf("Invoking Vertex AI model %s in project %s\n", modelName, projectId)
+ resp, err := client.GenerativeModel(modelName).GenerateContent(
+ ctx,
+ genai.Text("Tell me a joke about cloud security."),
+ )
+ if err != nil {
+ if isNotFound(err) {
+ log.Printf("Model %s not available in this project, trying next\n", modelName)
+ continue
+ }
+ return fmt.Errorf("failed to invoke Vertex AI model: %w", err)
+ }
+
+ if len(resp.Candidates) == 0 || len(resp.Candidates[0].Content.Parts) == 0 {
+ return fmt.Errorf("received empty response from Vertex AI model %s", modelName)
+ }
+
+ log.Printf("Successfully invoked Vertex AI model %s. Response: %v\n",
+ modelName, resp.Candidates[0].Content.Parts[0])
+ return nil
+ }
+
+ return fmt.Errorf("no Vertex AI model available in project %s (tried: %s) — ensure the Vertex AI API is enabled",
+ projectId, strings.Join(candidateModels, ", "))
+}
+
+// isNotFound returns true when the gRPC error indicates the model does not exist
+// or is not accessible in this project.
+func isNotFound(err error) bool {
+ msg := err.Error()
+ return strings.Contains(msg, "NOT_FOUND") ||
+ strings.Contains(msg, "code = NotFound") ||
+ strings.Contains(msg, "was not found")
+}
diff --git a/v2/internal/attacktechniques/main.go b/v2/internal/attacktechniques/main.go
index 48c792fb1..2729e25b3 100644
--- a/v2/internal/attacktechniques/main.go
+++ b/v2/internal/attacktechniques/main.go
@@ -83,6 +83,7 @@ import (
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image"
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/exfiltration/share-compute-snapshot"
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/impact/create-gpu-vm"
+ _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/impact/invoke-vertex-ai-model"
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/impact/create-instances-in-multiple-zones"
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/initial-access/use-compute-sa-outside-gcp"
_ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/lateral-movement/add-sshkey-instance-metadata"