exaai-agent 2.0.9__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {exaai_agent-2.0.9.dist-info → exaai_agent-2.2.0.dist-info}/METADATA +72 -42
  2. {exaai_agent-2.0.9.dist-info → exaai_agent-2.2.0.dist-info}/RECORD +34 -22
  3. {exaai_agent-2.0.9.dist-info → exaai_agent-2.2.0.dist-info}/WHEEL +1 -1
  4. exaaiagnt/dashboard/server.py +99 -0
  5. exaaiagnt/dashboard/templates/index.html +232 -0
  6. exaaiagnt/interface/cli.py +62 -30
  7. exaaiagnt/interface/main.py +11 -1
  8. exaaiagnt/interface/tui.py +12 -8
  9. exaaiagnt/llm/llm.py +43 -8
  10. exaaiagnt/llm/llm_traffic_controller.py +5 -3
  11. exaaiagnt/prompts/README.md +3 -1
  12. exaaiagnt/prompts/auto_loader.py +31 -0
  13. exaaiagnt/prompts/cloud/azure_cloud_security.jinja +126 -0
  14. exaaiagnt/prompts/cloud/gcp_cloud_security.jinja +158 -0
  15. exaaiagnt/prompts/cloud/kubernetes_security.jinja +97 -0
  16. exaaiagnt/prompts/vulnerabilities/prompt_injection.jinja +276 -0
  17. exaaiagnt/runtime/tool_manager.py +12 -3
  18. exaaiagnt/telemetry/tracer.py +17 -1
  19. exaaiagnt/tools/__init__.py +24 -0
  20. exaaiagnt/tools/executor.py +16 -4
  21. exaaiagnt/tools/k8s_scanner/__init__.py +29 -0
  22. exaaiagnt/tools/k8s_scanner/k8s_actions.py +319 -0
  23. exaaiagnt/tools/k8s_scanner/k8s_actions_schema.xml +36 -0
  24. exaaiagnt/tools/prompt_injection/__init__.py +26 -0
  25. exaaiagnt/tools/prompt_injection/prompt_injection_actions.py +712 -0
  26. exaaiagnt/tools/prompt_injection/prompt_injection_actions_schema.xml +28 -0
  27. exaaiagnt/tools/python/python_instance.py +16 -1
  28. exaaiagnt/tools/reporting/reporting_actions.py +34 -5
  29. exaaiagnt/tools/response_analyzer.py +5 -3
  30. exaaiagnt/tools/smart_fuzzer.py +5 -3
  31. exaaiagnt/tools/vuln_validator.py +5 -3
  32. exaaiagnt/tools/web_search/web_search_actions.py +4 -2
  33. {exaai_agent-2.0.9.dist-info → exaai_agent-2.2.0.dist-info}/entry_points.txt +0 -0
  34. {exaai_agent-2.0.9.dist-info → exaai_agent-2.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -30,39 +30,66 @@ BANNER = r"""
30
30
  """
31
31
 
32
32
 
33
+ from exaaiagnt.dashboard.server import start_dashboard
34
+
33
35
  async def run_cli(args: Any) -> None: # noqa: PLR0915
34
- console = Console()
35
-
36
- # Clear screen and show banner
37
- console.clear()
38
- console.print()
39
- console.print(BANNER, style="bold cyan", justify="center")
40
- console.print("[bold purple]Advanced AI-Powered Cybersecurity Agent[/]", justify="center")
41
- console.print("[dim]v2.0.0[/]", justify="center")
42
- console.print()
36
+ # Start the live dashboard
37
+ try:
38
+ start_dashboard()
39
+ console_temp = Console()
40
+ console_temp.print("[bold green]🚀 Live Dashboard available at: http://localhost:8000[/]")
41
+ except Exception as e:
42
+ import logging
43
+ logging.error(f"Failed to start dashboard: {e}")
43
44
 
44
- # Target info table
45
- target_table = Table(show_header=True, header_style="bold cyan", border_style="cyan")
46
- target_table.add_column("Type", style="dim")
47
- target_table.add_column("Target", style="white")
48
-
49
- for target_info in args.targets_info:
50
- target_type = target_info.get("type", "URL")
51
- target_table.add_row(target_type, target_info["original"])
45
+ # Detect if running in a real terminal or headless (pipe/background)
46
+ is_tty = sys.stdout.isatty()
47
+ console = Console(force_terminal=is_tty, no_color=not is_tty)
52
48
 
53
- console.print(Panel(target_table, title="[bold cyan]🎯 Targets", border_style="cyan"))
54
- console.print()
49
+ if is_tty:
50
+ # Clear screen and show banner only in interactive terminal
51
+ console.clear()
52
+ console.print()
53
+ console.print(BANNER, style="bold cyan", justify="center")
54
+ console.print("[bold purple]Advanced AI-Powered Cybersecurity Agent[/]", justify="center")
55
+ console.print("[dim]v2.1.2[/]", justify="center")
56
+ console.print()
57
+ else:
58
+ # Simple text output for headless/pipe mode
59
+ print("=" * 50)
60
+ print("ExaAiAgent - AI-Powered Security Scanner")
61
+ print("=" * 50)
62
+
63
+ if is_tty:
64
+ # Target info table (rich formatting)
65
+ target_table = Table(show_header=True, header_style="bold cyan", border_style="cyan")
66
+ target_table.add_column("Type", style="dim")
67
+ target_table.add_column("Target", style="white")
68
+
69
+ for target_info in args.targets_info:
70
+ target_type = target_info.get("type", "URL")
71
+ target_table.add_row(target_type, target_info["original"])
72
+
73
+ console.print(Panel(target_table, title="[bold cyan]🎯 Targets", border_style="cyan"))
74
+ console.print()
55
75
 
56
- # Config info
57
- config_text = Text()
58
- config_text.append("📁 Results: ", style="dim")
59
- config_text.append(f"exaai_runs/{args.run_name}\n", style="white")
60
- if args.instruction:
61
- config_text.append("📝 Instruction: ", style="dim")
62
- config_text.append(f"{args.instruction[:100]}{'...' if len(args.instruction) > 100 else ''}", style="white")
63
-
64
- console.print(Panel(config_text, title="[bold green]⚙️ Configuration", border_style="green"))
65
- console.print()
76
+ # Config info
77
+ config_text = Text()
78
+ config_text.append("📁 Results: ", style="dim")
79
+ config_text.append(f"exaai_runs/{args.run_name}\n", style="white")
80
+ if args.instruction:
81
+ config_text.append("📝 Instruction: ", style="dim")
82
+ config_text.append(f"{args.instruction[:100]}{'...' if len(args.instruction) > 100 else ''}", style="white")
83
+
84
+ console.print(Panel(config_text, title="[bold green]⚙️ Configuration", border_style="green"))
85
+ console.print()
86
+ else:
87
+ # Simple text output for headless mode
88
+ print(f"Targets: {[t['original'] for t in args.targets_info]}")
89
+ print(f"Results: exaai_runs/{args.run_name}")
90
+ if args.instruction:
91
+ print(f"Instruction: {args.instruction[:100]}")
92
+ print("-" * 50)
66
93
 
67
94
  scan_config = {
68
95
  "scan_id": args.run_name,
@@ -71,7 +98,12 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
71
98
  "run_name": args.run_name,
72
99
  }
73
100
 
74
- llm_config = LLMConfig()
101
+ # Handle prompt modules
102
+ prompt_modules = None
103
+ if getattr(args, "prompt_modules", None):
104
+ prompt_modules = [m.strip() for m in args.prompt_modules.split(",")]
105
+
106
+ llm_config = LLMConfig(prompt_modules=prompt_modules)
75
107
  agent_config = {
76
108
  "llm_config": llm_config,
77
109
  "max_iterations": 300,
@@ -242,7 +242,7 @@ async def warm_up_llm() -> None:
242
242
 
243
243
  def get_version() -> str:
244
244
  """Get the current ExaAi version."""
245
- return "2.1.0"
245
+ return "2.1.2"
246
246
 
247
247
 
248
248
  def parse_arguments() -> argparse.Namespace:
@@ -276,6 +276,10 @@ Examples:
276
276
  # Custom instructions
277
277
  exaai -t example.com -i "Focus on authentication vulnerabilities"
278
278
  exaai -t example.com --instruction ./instructions.txt
279
+
280
+ # Specific security modules
281
+ exaai -t example.com --prompt-modules kubernetes_security,cloud_security
282
+ exaai -t example.com --prompt-modules prompt_injection
279
283
  """,
280
284
  )
281
285
 
@@ -306,6 +310,12 @@ Examples:
306
310
  "or test credentials (e.g., 'Use the following credentials: admin:password123'). "
307
311
  "You can also provide a path to a file containing detailed instructions.",
308
312
  )
313
+ parser.add_argument(
314
+ "--prompt-modules",
315
+ type=str,
316
+ help="Comma-separated list of prompt modules to load (e.g., 'kubernetes_security,prompt_injection'). "
317
+ "Overrides auto-detection.",
318
+ )
309
319
  parser.add_argument(
310
320
  "--run-name",
311
321
  type=str,
@@ -45,7 +45,7 @@ def get_package_version() -> str:
45
45
  return pkg_version("exaai-agent")
46
46
  except PackageNotFoundError:
47
47
  # Fallback version if package not installed
48
- return "2.0.4"
48
+ return "2.1.2"
49
49
 
50
50
 
51
51
  class ChatTextArea(TextArea): # type: ignore[misc]
@@ -80,7 +80,7 @@ class SplashScreen(Static): # type: ignore[misc]
80
80
  NEON_ORANGE = "#ff8800"
81
81
  SOFT_WHITE = "#e0e0e0"
82
82
 
83
- # Enhanced ASCII Logo - ExaAi v2.0.4
83
+ # Enhanced ASCII Logo - ExaAi v2.1.2
84
84
  BANNER = r"""
85
85
  ███████╗██╗ ██╗ █████╗ █████╗ ██╗
86
86
  ██╔════╝╚██╗██╔╝██╔══██╗ ██╔══██╗██║
@@ -104,7 +104,7 @@ class SplashScreen(Static): # type: ignore[misc]
104
104
  self._animation_step = 0
105
105
  self._animation_timer: Timer | None = None
106
106
  self._panel_static: Static | None = None
107
- self._version = "2.1.0"
107
+ self._version = "2.1.2"
108
108
 
109
109
  def compose(self) -> ComposeResult:
110
110
  self._version = get_package_version()
@@ -181,14 +181,14 @@ class SplashScreen(Static): # type: ignore[misc]
181
181
  return text
182
182
 
183
183
  def _build_new_features_text(self) -> Text:
184
- """Build new features highlight for v2.0.4."""
184
+ """Build new features highlight for v2.1.0."""
185
185
  text = Text("🔥 ", style=Style(color=self.NEON_ORANGE))
186
186
  text.append("NEW: ", style=Style(color=self.NEON_ORANGE, bold=True))
187
- text.append("React2Shell", style=Style(color=self.NEON_PINK))
187
+ text.append("K8s Security", style=Style(color=self.NEON_PINK))
188
188
  text.append(" • ", style=Style(color=self.SOFT_WHITE, dim=True))
189
- text.append("Cloud Security", style=Style(color=self.NEON_CYAN))
189
+ text.append("Prompt Injection", style=Style(color=self.NEON_CYAN))
190
190
  text.append(" • ", style=Style(color=self.SOFT_WHITE, dim=True))
191
- text.append("Auto-Discovery", style=Style(color=self.NEON_GREEN))
191
+ text.append("Azure/GCP", style=Style(color=self.NEON_GREEN))
192
192
  return text
193
193
 
194
194
 
@@ -391,7 +391,11 @@ class ExaaiTUIApp(App): # type: ignore[misc]
391
391
  }
392
392
 
393
393
  def _build_agent_config(self, args: argparse.Namespace) -> dict[str, Any]:
394
- llm_config = LLMConfig()
394
+ prompt_modules = None
395
+ if getattr(args, "prompt_modules", None):
396
+ prompt_modules = [m.strip() for m in args.prompt_modules.split(",")]
397
+
398
+ llm_config = LLMConfig(prompt_modules=prompt_modules)
395
399
 
396
400
  config = {
397
401
  "llm_config": llm_config,
exaaiagnt/llm/llm.py CHANGED
@@ -424,19 +424,54 @@ class LLM:
424
424
  else:
425
425
  completion_args["reasoning_effort"] = "high"
426
426
 
427
- # Use Adaptive Traffic Controller for intelligent rate limiting
427
+ # Use Adaptive Traffic Controller for intelligent rate limiting with retries
428
428
  controller = get_traffic_controller()
429
429
  agent_id = self.agent_id or "unknown_agent"
430
430
 
431
431
  async def do_request():
432
- from litellm import completion
433
- return completion(**completion_args, stream=False)
434
-
435
- response = await controller.queue_request(
436
- do_request,
437
- agent_id=agent_id,
438
- priority=RequestPriority.NORMAL
432
+ try:
433
+ from litellm import completion
434
+ return await completion(**completion_args, stream=False)
435
+ except litellm.RateLimitError:
436
+ # Let tenacity (in controller) handle retry
437
+ raise
438
+ except Exception as e:
439
+ # Log other transient errors for potential retry
440
+ logger.warning(f"Transient LLM error: {e}")
441
+ raise
442
+
443
+ # Wrap in retry logic
444
+ from tenacity import (
445
+ retry,
446
+ stop_after_attempt,
447
+ wait_exponential,
448
+ retry_if_exception_type,
449
+ )
450
+ import litellm
451
+
452
+ @retry(
453
+ retry=retry_if_exception_type((
454
+ litellm.RateLimitError,
455
+ litellm.ServiceUnavailableError,
456
+ litellm.APIConnectionError,
457
+ litellm.Timeout
458
+ )),
459
+ wait=wait_exponential(multiplier=1, min=4, max=60),
460
+ stop=stop_after_attempt(5),
461
+ reraise=True
439
462
  )
463
+ async def execute_with_retries():
464
+ return await controller.queue_request(
465
+ do_request,
466
+ agent_id=agent_id,
467
+ priority=RequestPriority.NORMAL
468
+ )
469
+
470
+ try:
471
+ response = await execute_with_retries()
472
+ except Exception:
473
+ self._total_stats.failed_requests += 1
474
+ raise
440
475
 
441
476
  self._total_stats.requests += 1
442
477
  self._last_request_stats = RequestStats(requests=1)
@@ -54,11 +54,13 @@ class AdaptiveLLMController:
54
54
  """
55
55
 
56
56
  _instance: Optional["AdaptiveLLMController"] = None
57
+ _lock_cls = __import__("threading").Lock()
57
58
 
58
59
  def __new__(cls) -> "AdaptiveLLMController":
59
- if cls._instance is None:
60
- cls._instance = super().__new__(cls)
61
- cls._instance._initialized = False
60
+ with cls._lock_cls:
61
+ if cls._instance is None:
62
+ cls._instance = super().__new__(cls)
63
+ cls._instance._initialized = False
62
64
  return cls._instance
63
65
 
64
66
  def __init__(self):
@@ -43,12 +43,14 @@ The modules are dynamically injected into the agent's system prompt, allowing it
43
43
  | `race_conditions` | Race condition and TOCTOU exploits |
44
44
  | `path_traversal` | Directory traversal attacks |
45
45
 
46
- ### NEW: Advanced Modules
46
+ ### NEW: Advanced Modules (v2.1)
47
47
 
48
48
  | Module | Description |
49
49
  |--------|-------------|
50
50
  | `api_security` | REST, GraphQL, gRPC API security testing |
51
51
  | `cloud_security` | AWS, Azure, GCP security assessment |
52
+ | `kubernetes_security` | **NEW!** K8s RBAC, Pod Security, Network Policy audit |
53
+ | `prompt_injection` | **NEW!** AI/LLM prompt injection & jailbreaking |
52
54
  | `reconnaissance_osint` | Reconnaissance and OSINT techniques |
53
55
  | `privilege_escalation` | Linux/Windows privilege escalation |
54
56
  | `high_impact_bugs` | Bug bounty hunting for critical vulns |
@@ -210,6 +210,37 @@ MODULE_PATTERNS = {
210
210
  ],
211
211
  "keywords": ["aws", "s3", "ec2", "lambda", "azure", "gcp", "cloud", "bucket", "metadata"],
212
212
  },
213
+
214
+ # Kubernetes Security (NEW v2.1)
215
+ "kubernetes_security": {
216
+ "url_patterns": [
217
+ r"/api/v1/",
218
+ r"/apis/",
219
+ r":6443",
220
+ r":10250",
221
+ r":8443",
222
+ ],
223
+ "keywords": ["kubernetes", "k8s", "kubectl", "pod", "deployment", "service",
224
+ "ingress", "helm", "kubelet", "etcd", "rbac", "namespace"],
225
+ },
226
+
227
+ # AI/LLM Prompt Injection (NEW v2.1)
228
+ "prompt_injection": {
229
+ "url_patterns": [
230
+ r"/chat",
231
+ r"/completions",
232
+ r"/generate",
233
+ r"/ask",
234
+ r"/ai",
235
+ r"/llm",
236
+ r"/v1/chat",
237
+ r"/v1/completions",
238
+ r"/assistant",
239
+ ],
240
+ "keywords": ["openai", "anthropic", "llm", "gpt", "claude", "chatbot",
241
+ "ai assistant", "langchain", "llama", "gemini", "copilot",
242
+ "rag", "embedding", "vector", "prompt"],
243
+ },
213
244
  }
214
245
 
215
246
 
@@ -0,0 +1,126 @@
1
+ <azure_security_guide>
2
+ <title>AZURE CLOUD SECURITY AUDIT</title>
3
+
4
+ <critical>Azure is the enterprise cloud. Misconfigurations in Azure AD, Blob Storage, and Managed Identities are primary attack vectors. Default settings often expose resources publicly. Entra ID (formerly Azure AD) is the crown jewel - compromise it, own everything.</critical>
5
+
6
+ <scope>
7
+ - Identity: Azure AD (Entra ID), Service Principals, Managed Identities
8
+ - Storage: Blob Storage, Azure Files, Data Lake
9
+ - Compute: VMs, App Service, Functions, AKS
10
+ - Network: NSGs, Azure Firewall, Private Link, VNet
11
+ - Secrets: Key Vault, App Configuration
12
+ </scope>
13
+
14
+ <methodology>
15
+ 1. **Reconnaissance**: Enumerate subscriptions, resource groups, and public assets.
16
+ 2. **Identity Audit**: Check Azure AD roles, conditional access policies, MFA enforcement.
17
+ 3. **Storage Audit**: Scan for public blobs, SAS token misuse, anonymous access.
18
+ 4. **Compute Audit**: Check VM extensions, managed identity permissions, IMDS exposure.
19
+ 5. **Network Audit**: Verify NSG rules, private endpoints, exposed services.
20
+ 6. **Secrets Audit**: Key Vault access policies, secret rotation, RBAC vs Access Policies.
21
+ </methodology>
22
+
23
+ <attack_vectors>
24
+ - **Public Blob Storage**: Anonymous read access to containers.
25
+ - **SAS Token Abuse**: Overly permissive or leaked SAS tokens.
26
+ - **IMDS v1**: Instance metadata service for credential theft (169.254.169.254).
27
+ - **Service Principal Secrets**: Exposed or non-rotating SP credentials.
28
+ - **Managed Identity Abuse**: Over-privileged managed identities on VMs/Functions.
29
+ - **Azure AD Misconfig**: Guest users with elevated roles, no conditional access.
30
+ - **Key Vault RBAC**: Users with Key Vault Contributor can read secrets.
31
+ - **ARM Template Secrets**: Secrets hardcoded in deployments.
32
+ </attack_vectors>
33
+
34
+ <critical_checks>
35
+ <storage>
36
+ # Check for public blob containers
37
+ az storage container list --account-name <storage> --query "[?properties.publicAccess!=null]"
38
+
39
+ # Check for anonymous access
40
+ az storage blob list --container-name <container> --account-name <storage> --auth-mode key
41
+ </storage>
42
+
43
+ <identity>
44
+ # List Service Principals with secrets
45
+ az ad sp list --all --query "[?passwordCredentials]"
46
+
47
+ # Check for high-privilege role assignments
48
+ az role assignment list --all --query "[?roleDefinitionName=='Owner' || roleDefinitionName=='Contributor']"
49
+
50
+ # Managed Identity check
51
+ az vm identity show --name <vm> --resource-group <rg>
52
+ </identity>
53
+
54
+ <network>
55
+ # Check for open NSG rules (any source)
56
+ az network nsg rule list --nsg-name <nsg> --resource-group <rg> --query "[?sourceAddressPrefix=='*' && access=='Allow']"
57
+
58
+ # Find public IPs
59
+ az network public-ip list --query "[?ipAddress!=null]"
60
+ </network>
61
+
62
+ <keyvault>
63
+ # Check Key Vault access policies
64
+ az keyvault show --name <vault> --query "properties.accessPolicies"
65
+
66
+ # Check for RBAC mode (preferred)
67
+ az keyvault show --name <vault> --query "properties.enableRbacAuthorization"
68
+ </keyvault>
69
+ </critical_checks>
70
+
71
+ <automation_script>
72
+ ```python
73
+ import subprocess
74
+ import json
75
+
76
+ def run_az(cmd: list) -> dict:
77
+ """Run Azure CLI command and return JSON."""
78
+ result = subprocess.run(["az"] + cmd + ["-o", "json"], capture_output=True, text=True)
79
+ return json.loads(result.stdout) if result.returncode == 0 else {}
80
+
81
+ def audit_azure():
82
+ findings = []
83
+
84
+ # Check public storage containers
85
+ accounts = run_az(["storage", "account", "list"])
86
+ for acc in accounts:
87
+ containers = run_az(["storage", "container", "list", "--account-name", acc["name"], "--auth-mode", "login"])
88
+ for container in containers:
89
+ if container.get("properties", {}).get("publicAccess"):
90
+ findings.append({
91
+ "severity": "CRITICAL",
92
+ "title": "Public Blob Container",
93
+ "resource": f"{acc['name']}/{container['name']}",
94
+ "remediation": "Set publicAccess to None"
95
+ })
96
+
97
+ # Check privileged role assignments
98
+ assignments = run_az(["role", "assignment", "list", "--all"])
99
+ for assignment in assignments:
100
+ if assignment.get("roleDefinitionName") in ["Owner", "User Access Administrator"]:
101
+ findings.append({
102
+ "severity": "HIGH",
103
+ "title": f"Privileged Role: {assignment['roleDefinitionName']}",
104
+ "resource": assignment.get("principalName"),
105
+ "remediation": "Review and apply least privilege"
106
+ })
107
+
108
+ return findings
109
+
110
+ if __name__ == "__main__":
111
+ for f in audit_azure():
112
+ print(f"[{f['severity']}] {f['title']}: {f['resource']}")
113
+ ```
114
+ </automation_script>
115
+
116
+ <remediation_guide>
117
+ 1. **Disable Public Blob Access**: Set `allowBlobPublicAccess: false` at storage account level.
118
+ 2. **Use Managed Identities**: Avoid Service Principal secrets where possible.
119
+ 3. **Enable MFA**: Enforce MFA for all users via Conditional Access.
120
+ 4. **Use RBAC for Key Vault**: Switch from Access Policies to Azure RBAC.
121
+ 5. **Private Endpoints**: Use Private Link for storage, databases, and Key Vault.
122
+ 6. **Enable Defender for Cloud**: Turn on security recommendations and alerts.
123
+ 7. **Rotate Secrets**: Automate rotation for Service Principal secrets and keys.
124
+ </remediation_guide>
125
+
126
+ </azure_security_guide>
@@ -0,0 +1,158 @@
1
+ <gcp_security_guide>
2
+ <title>GOOGLE CLOUD PLATFORM (GCP) SECURITY AUDIT</title>
3
+
4
+ <critical>GCP's IAM model is powerful but complex. Over-permissive service accounts, public Cloud Storage buckets, and metadata service abuse are the top attack vectors. Workload Identity Federation and VPC Service Controls are critical but often misconfigured.</critical>
5
+
6
+ <scope>
7
+ - Identity: IAM policies, Service Accounts, Workload Identity
8
+ - Storage: Cloud Storage (GCS), BigQuery, Firestore
9
+ - Compute: Compute Engine, Cloud Functions, Cloud Run, GKE
10
+ - Network: VPC, Firewall Rules, Private Google Access
11
+ - Secrets: Secret Manager, KMS
12
+ </scope>
13
+
14
+ <methodology>
15
+ 1. **Reconnaissance**: Enumerate projects, service accounts, and public assets.
16
+ 2. **IAM Audit**: Check for overly permissive roles (Editor, Owner) on service accounts.
17
+ 3. **Storage Audit**: Scan for public buckets, allUsers/allAuthenticatedUsers ACLs.
18
+ 4. **Compute Audit**: Check metadata server access, service account scopes, public IPs.
19
+ 5. **Network Audit**: Verify firewall rules, VPC Service Controls, Private Google Access.
20
+ 6. **Secrets Audit**: Secret Manager access, KMS key permissions.
21
+ </methodology>
22
+
23
+ <attack_vectors>
24
+ - **Public GCS Buckets**: `allUsers` read access on sensitive buckets.
25
+ - **Metadata Server Abuse**: `http://metadata.google.internal/computeMetadata/v1/` for token theft.
26
+ - **Service Account Key Leakage**: JSON keys committed to repos or logs.
27
+ - **Default Service Account**: Compute Engine default SA with Editor role.
28
+ - **Over-privileged IAM**: Service accounts with `roles/editor` or `roles/owner`.
29
+ - **Workload Identity Misconfiguration**: Allowing external identities to impersonate SAs.
30
+ - **Public Cloud Functions**: Functions with `allUsers` invoker permission.
31
+ - **BigQuery Public Datasets**: Datasets readable by `allAuthenticatedUsers`.
32
+ </attack_vectors>
33
+
34
+ <critical_checks>
35
+ <storage>
36
+ # Check for public buckets
37
+ gsutil iam get gs://<bucket> | grep -E "allUsers|allAuthenticatedUsers"
38
+
39
+ # List all buckets
40
+ gsutil ls
41
+
42
+ # Check bucket ACLs
43
+ gsutil acl get gs://<bucket>
44
+ </storage>
45
+
46
+ <iam>
47
+ # List all service accounts
48
+ gcloud iam service-accounts list
49
+
50
+ # Check service account keys (should be minimal)
51
+ gcloud iam service-accounts keys list --iam-account=<sa-email>
52
+
53
+ # Find over-privileged bindings
54
+ gcloud projects get-iam-policy <project> --format=json | jq '.bindings[] | select(.role | contains("owner") or contains("editor"))'
55
+
56
+ # Check for external members
57
+ gcloud projects get-iam-policy <project> --format=json | jq '.bindings[].members[] | select(contains("user:") | not)'
58
+ </iam>
59
+
60
+ <compute>
61
+ # Check default service account usage
62
+ gcloud compute instances list --format="table(name,serviceAccounts.email)"
63
+
64
+ # Metadata server access test (from compromised instance)
65
+ curl -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
66
+
67
+ # Check for public IPs
68
+ gcloud compute instances list --format="table(name,networkInterfaces[].accessConfigs[].natIP)"
69
+ </compute>
70
+
71
+ <functions>
72
+ # Check for public invocation
73
+ gcloud functions describe <function> --format="value(invokerMembers)"
74
+ # If contains "allUsers" = PUBLIC
75
+ </functions>
76
+
77
+ <firewall>
78
+ # List all firewall rules allowing 0.0.0.0/0
79
+ gcloud compute firewall-rules list --filter="sourceRanges=0.0.0.0/0" --format="table(name,allowed,direction)"
80
+ </firewall>
81
+ </critical_checks>
82
+
83
+ <automation_script>
84
+ ```python
85
+ import subprocess
86
+ import json
87
+
88
+ def run_gcloud(cmd: list) -> dict:
89
+ """Run gcloud command and return JSON."""
90
+ result = subprocess.run(["gcloud"] + cmd + ["--format=json"], capture_output=True, text=True)
91
+ return json.loads(result.stdout) if result.returncode == 0 else []
92
+
93
+ def audit_gcp(project: str):
94
+ findings = []
95
+
96
+ # Check for service account keys (should be 0 or 1)
97
+ sas = run_gcloud(["iam", "service-accounts", "list", f"--project={project}"])
98
+ for sa in sas:
99
+ keys = run_gcloud(["iam", "service-accounts", "keys", "list",
100
+ f"--iam-account={sa['email']}", f"--project={project}"])
101
+ user_keys = [k for k in keys if k.get("keyType") == "USER_MANAGED"]
102
+ if len(user_keys) > 0:
103
+ findings.append({
104
+ "severity": "HIGH",
105
+ "title": "User-Managed SA Keys Exist",
106
+ "resource": sa["email"],
107
+ "details": f"{len(user_keys)} user-managed keys found",
108
+ "remediation": "Use Workload Identity or VM Service Accounts instead of keys"
109
+ })
110
+
111
+ # Check IAM for overly permissive roles
112
+ policy = run_gcloud(["projects", "get-iam-policy", project])
113
+ for binding in policy.get("bindings", []):
114
+ if any(role in binding.get("role", "") for role in ["owner", "editor"]):
115
+ for member in binding.get("members", []):
116
+ if member.startswith("serviceAccount:"):
117
+ findings.append({
118
+ "severity": "CRITICAL",
119
+ "title": f"Service Account with {binding['role']}",
120
+ "resource": member,
121
+ "remediation": "Replace with fine-grained roles"
122
+ })
123
+
124
+ # Check for public firewall rules
125
+ rules = run_gcloud(["compute", "firewall-rules", "list", f"--project={project}"])
126
+ for rule in rules:
127
+ if "0.0.0.0/0" in rule.get("sourceRanges", []):
128
+ if rule.get("allowed"):
129
+ findings.append({
130
+ "severity": "MEDIUM",
131
+ "title": "Firewall Rule Allows 0.0.0.0/0",
132
+ "resource": rule["name"],
133
+ "details": f"Allows: {rule['allowed']}",
134
+ "remediation": "Restrict source ranges to known IPs"
135
+ })
136
+
137
+ return findings
138
+
139
+ if __name__ == "__main__":
140
+ import sys
141
+ project = sys.argv[1] if len(sys.argv) > 1 else "your-project"
142
+ for f in audit_gcp(project):
143
+ print(f"[{f['severity']}] {f['title']}: {f['resource']}")
144
+ ```
145
+ </automation_script>
146
+
147
+ <remediation_guide>
148
+ 1. **Remove SA Keys**: Delete all user-managed service account keys. Use Workload Identity.
149
+ 2. **Least Privilege IAM**: Replace Editor/Owner with specific roles.
150
+ 3. **Private Buckets**: Remove allUsers/allAuthenticatedUsers from bucket IAM.
151
+ 4. **VPC Service Controls**: Enable for sensitive projects.
152
+ 5. **OS Login**: Use OS Login instead of SSH keys for VM access.
153
+ 6. **Private Google Access**: Enable for subnets to access Google APIs privately.
154
+ 7. **Security Command Center**: Enable for vulnerability and threat detection.
155
+ 8. **Organization Policies**: Enforce constraints (no public IPs, no external sharing).
156
+ </remediation_guide>
157
+
158
+ </gcp_security_guide>