Back to skill

Security audit

Dialogflow CX to CX Agent Studio Migration Skill

Security checks for vulnerabilities and agentic risk

Overview

This migration skill mostly matches its stated purpose, but it needs review because it can send Google access tokens to unvalidated API URLs and makes durable cloud and local changes.

Install only if you understand that it will use your Google ADC identity, write exported Dialogflow agent contents to local disk, and create or modify CES resources. Use a non-production project or least-privilege service account, keep the default Google API endpoints, avoid custom base URLs unless you trust them completely, review the output directory for sensitive exported data, and prefer `--export-only` first when evaluating the migration.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/migrate.py:36
Finding

ADC Bearer Token Disclosure Through Unrestricted API Base URLs

Content
View full analysis
Dict[str, Any]: headers = kwargs.pop("headers", {}) headers.setdefault("Authorization", f"Bearer {token}") headers.setdefault("Content-Type", "application/json") response = requests.request(method, url, headers=headers, **kwargs) ``` ```python def wait_operation(base_url: str, op_name: str, token: str, timeout_s: int = 900) -> Dict[str, Any]: start = time.time() delay = 2.0 if op_name.startswith("http"): op_url = op_name else: op_url = f"{base_url}/{op_name}" ``` ```python parser.add_argument("--dfcx-base-url", default=DEFAULT_DFCX_BASE) parser.add_argument("--ces-base-url", default=DEFAULT_CES_BASE) ``` ```python token = get_access_token(list(set(DFCX_SCOPES + CES_SCOPES))) dfcx_agent = get_dfcx_agent(args.dfcx_base_url, args.dfcx_agent, token) ``` ### Technical Analysis The script accepts the Dialogflow CX and CES API base URLs directly from command-line arguments without validating their schemes, hosts, ports, or origins. Every request made through `http_request` receives the Google ADC bearer token in its `Authorization` header, regardless of the request destination. The acquired token requests the union of the Cloud Platform, Dialogflow, and CES scopes. Consequently, a custom endpoint does not merely receive migration data; it receives a live Google OAuth bearer token whose effective authority is determined by both the requested scopes and the IAM permissions of the executing identity. The long-running-operation logic introduces an additional trust-boundary issue. If an operation name starts with `http`, it is treated as an abs ...[truncated 2048 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/migrate.py:115
Finding

Unbounded Extraction and Processing of Remotely Supplied ZIP Archives

Content
View full analysis
Dict[str, Any]: summary: Dict[str, Any] = { "component_counts": {}, "components": {}, "unclassified_files": [], } component_index: Dict[str, List[Dict[str, Any]]] = {} if not zipfile.is_zipfile(io.BytesIO(zip_bytes)): summary["note"] = "Export content is not a zip archive. Skipping detailed parsing." return summary os.makedirs(output_dir, exist_ok=True) zf = zipfile.ZipFile(io.BytesIO(zip_bytes)) zf.extractall(output_dir) for path in zf.namelist(): if not path.endswith(".json"): continue if path.endswith("/agent.json") or path == "agent.json": data = parse_json_from_zip(zf, path) summary["agent"] = { "name": data.get("name"), "displayName": data.get("displayName"), "defaultLanguageCode": data.get("defaultLanguageCode"), "supportedLanguageCodes": data.get("supportedLanguageCodes", []), "timeZone": data.get("timeZone"), "startFlow": data.get("startFlow"), "startPlaybook": data.get("startPlaybook"), } continue category = classify_path(path) if category is None: summary["unclassified_files"].append(path) continue data = parse_json_from_zip(zf, path) entry = { "file": path, "name": data.get("name"), "displayName": data.get("displayName"), } component_index.setdefault(category, []).append(entry) ``` ### Technical Analysis The script checks only whether the supplied bytes have a valid ZIP structure before calling `extractall`. It ...[truncated 2532 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/migrate.py (reported line 34)May include surrounding context.

python
if not creds.valid:
        creds.refresh(Request())
    if not creds.token:
        raise RuntimeError("Failed to obtain access token.")
    return creds.token

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises and documents operations that read and write local files and make network calls to Google APIs, but it does not declare any explicit tool scope or permissions boundary in the skill metadata. This creates a transparency and containment problem: users and enforcement layers may not understand that the skill can export sensitive agent data to disk and create or modify remote CES resources.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description explains what the migration does, but it does not clearly warn users that execution will create or modify CES resources and write exported Dialogflow CX agent data to local disk. This omission can lead to unintended data exposure, persistence of potentially sensitive configuration artifacts, and accidental changes in a production cloud environment.

Content

No source excerpt is available for this finding.