Back to skill

Security audit

AuditClaw Gcp

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to perform legitimate GCP compliance collection, but it asks users to grant broad project-wide read access and create a long-lived cloud key without enough scoping or credential-safety guidance.

Install only if you are comfortable granting this skill broad read visibility into the target GCP project and storing compliance evidence locally. Prefer keyless authentication or a tightly scoped custom role where possible; if you use a service account JSON key, keep it outside repositories, restrict file permissions, rotate it, and revoke it when no longer needed. Treat the local GRC database as sensitive compliance data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/gcp-roles.json:14
Finding
Excessive Project-Wide IAM Permissions Violate Least Privilege<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gcp-roles.json:14-44`; related setup instructions in `SKILL.md:83-100` **Vulnerability Type**: Excessive cloud IAM privileges **Risk Level**: Medium ### Vulnerable Code ```json "roles": [ { "role": "roles/viewer", "scope": "Project", "reason": "Read access to most GCP resources (storage, compute, firewall, BigQuery)" }, { "role": "roles/iam.securityReviewer", "scope": "Project", "reason": "Read access to IAM policies, service account keys, and security settings" }, { "role": "roles/cloudsql.viewer", "scope": "Project", "reason": "Read access to Cloud SQL instance configurations and SSL settings" }, { "role": "roles/logging.viewer", "scope": "Project", "reason": "Read access to audit log configuration and log sinks" }, { "role": "roles/dns.reader", "scope": "Project", "reason": "Read access to Cloud DNS zones for DNSSEC verification" }, { "role": "roles/cloudkms.viewer", "scope": "Project", "reason": "Read access to KMS key rotation policies" } ] ``` The documented setup grants every role at project scope: ```bash for role in roles/viewer roles/iam.securityReviewer roles/cloudsql.viewer roles/logging.viewer roles/dns.reader roles/cloudkms.viewer; do gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:auditclaw-scanner@PROJECT_ID.iam.gserviceaccount.com \ --role=$role done ``` ### Technical Analysis The Skill implements narrowly defined read-only checks, but its setup grants six broad predefined roles across the entire target project. In particular, `roles/viewer`, `roles/iam.securityReviewer`, and `roles/logging.viewer` provide access to substantially more project metadata than is necessary for the implemented checks. The code only requires selected list/get operations for bucket settings, firewall rules, IAM policy bindings, service-account key metadata, logging con ...[truncated 1954 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the broad predefined-role bundle with a dedicated GCP custom role containing only the exact list/get permissions exercised by the check modules. 2. Split permissions by check category so users running only selected checks do not need permissions for unrelated services. 3. Document the precise API permissions required by each check and provide separate minimal-role deployment examples. 4. Prefer short-lived Application Default Credentials, service-account impersonation, or Workload Identity Federation over downloadable service-account JSON keys. 5. If JSON keys remain supported: - Create them only when no keyless alternative is available. - Store them outside repositories and shared directories. - Apply restrictive filesystem permissions. - Rotate them regularly. - Revoke and securely delete them after use. 6. Add deployment validation that warns when the scanner identity has roles or permissions beyond the documented minimal set. 7. Where practical, constrain access using IAM Conditions and organization policies. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gcp_evidence.py:228
Finding
Connection Test Reports Unexpected API Failures as Successful Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gcp_evidence.py:228-258` **Vulnerability Type**: Fail-open error handling and inaccurate security status reporting **Risk Level**: Medium ### Vulnerable Code ```python # Test Cloud Storage first (most common) try: list(gcs.Client(project=project_id).list_buckets(max_results=1)) results.append({"service": "Cloud Storage", "status": "ok", "detail": "accessible"}) passed += 1 except Exception as e: if "403" in str(e) or "Forbidden" in str(e): results.append({"service": "Cloud Storage", "status": "denied", "detail": str(e)[:200]}) failed += 1 else: results.append({"service": "Cloud Storage", "status": "ok", "detail": f"accessible ({type(e).__name__})"}) passed += 1 # Test remaining services for service_name, module_path, class_name, method_name, kwargs in optional_probes: try: mod = importlib.import_module(module_path) client_class = getattr(mod, class_name) if method_name: client = client_class() method = getattr(client, method_name) list(method(**kwargs)) else: client_class(project=project_id) results.append({"service": service_name, "status": "ok", "detail": "accessible"}) passed += 1 except ImportError: results.append({"service": service_name, "status": "skipped", "detail": "SDK not installed"}) except Exception as e: if "403" in str(e) or "PERMISSION_DENIED" in str(e): results.append({"service": service_name, "status": "denied", "detail": str(e)[:200]}) failed += 1 else: results.append({"service": service_name, "status": "ok", "detail": f"accessible ({type(e).__name__})"}) passed += 1 ``` ### Technical Analysis The connection test treats every exception that does not contain a small set of permission-denial strings as a successful service probe. Consequently, network ...[truncated 1956 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every unexpected exception as a failed or indeterminate probe, never as success. 2. Increment `passed` only after the requested API operation completes successfully. 3. Catch typed Google and gRPC exceptions, such as authentication, permission, unavailable-service, timeout, and quota exceptions. 4. Use structured HTTP or gRPC status codes instead of searching exception text. 5. Distinguish report states such as: - `ok`: the API call completed successfully. - `denied`: credentials were valid but lacked the required permission. - `unavailable`: the API or network was unavailable. - `authentication_error`: credentials could not be accepted. - `error`: another probe failure occurred. - `skipped`: the required SDK was not installed. 6. Set `all_passed` to true only when every required probe produced an explicit successful response. 7. Return a nonzero exit status when required services fail or are indeterminate so automation cannot mistake the test for success. 8. Add unit tests covering timeouts, disabled APIs, malformed requests, authentication failures, quota errors, server errors, and differently formatted permission-denial exceptions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared purpose emphasizes 'read-only checks,' but the skill also writes evidence and integration status into a local SQLite database and exposes a test-connection mode, while the documented check count/category mapping is inconsistent. This mismatch is dangerous because users and orchestrators may grant trust or permissions based on an incomplete description, leading to unexpected state changes, overbroad execution, or incorrect risk assumptions about what the skill actually does.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The markdown states that the skill runs checks against a GCP project and stores evidence in a shared database, which can affect user or organizational data handling. The description does not include any warning about what data is collected, persisted, or the implications of writing compliance evidence to shared storage.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises executable behavior and explicitly depends on environment variables and shell-invoked setup/usage commands, but it does not declare an explicit tool scope such as allowed-tools or permissions. That creates an authorization and transparency gap: an agent or reviewer cannot easily constrain or reason about what external capabilities the skill may exercise, increasing the chance of unintended command execution or environment access.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The setup guide instructs users to create a long-lived service account JSON key and place it on disk, but it provides no warning about secret sensitivity, storage protections, rotation, or safer alternatives. Service account keys are highly valuable credentials; if leaked through logs, backups, shell history, shared filesystems, or misconfigured file permissions, an attacker could gain ongoing read access to the GCP project and potentially pivot further depending on granted roles.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes the skill as performing '12 read-only checks' across GCP services, which suggests observational behavior. However, this script not only runs checks but also inserts evidence records and updates integration status in a SQLite database, making persistent state changes outside the read-only checking scope described in the manifest.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"--file-content", json.dumps(result, default=str),
    ]

    proc = subprocess.run(cmd, capture_output=True, text=True)
    if proc.returncode != 0:
        return _store_evidence_direct(db_path, check_name, result)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The function retrieves application default credentials and immediately uses them to call the Cloud SQL Admin API. While this is consistent with the check's purpose, the file contains no user-facing print/log statement or explicit warning that it will use ambient GCP credentials and contact Google APIs.

Missing User Warnings

Low
Confidence
78% confidence
Finding
This code instantiates a GCP KMS client and enumerates key rings across the project, which is a network/API operation that transmits project context to an external cloud service. While the function has an internal docstring, there is no user-facing prompt, logging, or warning indicating that cloud KMS inventory data will be queried.

Vague Triggers

Low
Confidence
76% confidence
Finding
This JSON manifest includes actionable setup commands for creating a service account, granting roles, and generating a key, but it does not describe when these commands should or should not be invoked. In a manifest-scoped file, the lack of trigger scope or negative examples can make activation or use conditions ambiguous for automation that consumes the manifest.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The connection test treats many unexpected exceptions as successful access, which can produce false 'ok' results even when APIs are unreachable, misconfigured, or failing for non-permission reasons. This can mislead operators into trusting broken monitoring or evidence collection, reducing visibility and potentially causing missed compliance or security issues.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
for service_name, module_path, class_name, method_name, kwargs in optional_probes:
        try:
            mod = importlib.import_module(module_path)
            client_class = getattr(mod, class_name)
            if method_name:
                client = client_class()
                method = getattr(client, method_name)
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
client_class = getattr(mod, class_name)
            if method_name:
                client = client_class()
                method = getattr(client, method_name)
                list(method(**kwargs))
            else:
                client_class(project=project_id)
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.