Back to skill

Security audit

GEO Visual Content Engine

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly aligned with e-commerce asset generation, but it has unsafe handling of store credentials, live publishing, and writable output paths that should be reviewed before installation.

Install only after reviewing the code paths that use Shopify and WooCommerce credentials. Use a test store first, avoid setting store admin credentials as ambient environment variables unless publishing is intended, use least-privilege tokens, validate store URLs, and constrain output paths to a dedicated directory.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
src/shopify.py:45
Finding
Shopify access token can be transmitted to an unvalidated host without publishing consent<![CDATA[ ## Vulnerability Details **File Location**: `src/shopify.py:45-55`, `src/shopify.py:82-95`, `src/main.py:81`, `src/main.py:268-287`, `src/main.py:625-626` **Vulnerability Type**: Unvalidated credential destination and constructor-triggered network access **Risk Level**: High ### Vulnerable Code ```python self.store_url = store_url or os.environ.get("SHOPIFY_STORE_URL", "") self.access_token = access_token or os.environ.get("SHOPIFY_ACCESS_TOKEN", "") self.api_version = "2024-01" self.base_url = f"https://{self.store_url}/admin/api/{self.api_version}" self.headers = { "Content-Type": "application/json", "X-Shopify-Access-Token": self.access_token } if self.access_token else {} self.connected = bool(self.store_url and self.access_token) ``` ```python try: response = requests.get( f"{self.base_url}/shop.json", headers=self.headers, timeout=10 ) ``` The connection check is invoked automatically during initialization: ```python # Check connections self._check_connections() ``` The JSON execution path allows the store URL to come from input while silently obtaining the token from the environment: ```python shopify_url = input_data.get("shopify_store_url") or os.environ.get("SHOPIFY_STORE_URL") shopify_token = input_data.get("shopify_access_token") or os.environ.get("SHOPIFY_ACCESS_TOKEN") ``` ### Technical Analysis The Shopify destination is built by directly interpolating `store_url` into an HTTPS URL. The implementation does not parse or validate the hostname, reject user-information components, enforce an approved Shopify domain, or prevent unexpected path and port components. More importantly, the code combines independently sourced trust domains: an input-controlled store URL may be paired with a privileged Shopify token obtained from the process environment. `EcommerceAutomator.__init__()` then calls `_check_connections()` unconditionally. Consequently, a network request carrying the `X-Shopify-Access ...[truncated 1647 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not instantiate or test Shopify connectivity unless direct Shopify publishing has been explicitly authorized for the current operation. 2. Never combine an input-supplied URL with a credential silently loaded from the environment. 3. Parse the URL using a strict URL parser and require: - HTTPS only. - No embedded username or password. - No fragments or unexpected query parameters. - No unexpected port. - A hostname ending in `.myshopify.com`, or a separately configured administrator-approved allowlist. 4. Store a trusted Shopify origin together with its credential rather than allowing callers to choose the destination. 5. Disable cross-origin redirects or verify every redirect destination before forwarding authentication headers. 6. Request a Shopify token containing only the scopes required for product export. 7. Replace constructor-side network activity with an explicit `connect()` or `publish()` operation invoked only after authorization. 8. Enforce the declared input schema before reading any fields. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/woocommerce.py:50
Finding
WooCommerce credentials are used automatically without HTTPS or destination validation<![CDATA[ ## Vulnerability Details **File Location**: `src/woocommerce.py:50-69`, `src/woocommerce.py:94-104`, `src/woocommerce.py:113-125`, `src/main.py:68-81`, `src/main.py:268-287` **Vulnerability Type**: Insecure authenticated endpoint handling and unauthorized connection testing **Risk Level**: High ### Vulnerable Code ```python self.store_url = store_url or os.environ.get("WOOCOMMERCE_STORE_URL", "") self.consumer_key = consumer_key or os.environ.get("WOOCOMMERCE_CONSUMER_KEY", "") self.consumer_secret = consumer_secret or os.environ.get("WOOCOMMERCE_CONSUMER_SECRET", "") # Ensure URL doesn't have trailing slash self.store_url = self.store_url.rstrip('/') # Setup OAuth1 authentication self.auth = None self.connected = False if self.consumer_key and self.consumer_secret: try: self.auth = OAuth1( self.consumer_key, client_secret=self.consumer_secret, signature_method="HMAC-SHA256", timestamp=str(int(time.time())) ) self.connected = bool(self.store_url) except Exception: self.connected = False ``` ```python def _get_api_url(self, endpoint: str) -> str: base = f"{self.store_url}/wp-json/{self.api_version}" return f"{base}/{endpoint.lstrip('/')}" ``` ```python try: response = requests.get( self._get_api_url("system_status"), auth=self.auth, timeout=10 ) ``` The authenticated connection test is initiated during automator construction: ```python self.woocommerce = WooCommerceIntegration( store_url=woo_store_url, consumer_key=woo_consumer_key, consumer_secret=woo_consumer_secret ) # Check connections self._check_connections() ``` ### Technical Analysis The integration accepts `WOOCOMMERCE_STORE_URL` without checking its scheme or origin. An HTTP URL is accepted, as is an arbitrary HTTPS host. The resulting endpoint is used with OAuth1 authentication. Although OAuth1 signs requests rather than necessarily transmitt ...[truncated 1930 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https` for every WooCommerce endpoint and reject HTTP URLs. 2. Parse and validate the configured URL before constructing authentication objects. 3. Reject embedded credentials, unexpected ports, fragments, and malformed hostnames. 4. Bind each credential to a pre-approved origin that untrusted workflow input cannot override. 5. Do not create OAuth authentication or test connectivity unless direct WooCommerce export is explicitly enabled. 6. Move connection testing out of the constructor and into an explicit, authorized operation. 7. Disable redirects for authenticated API requests or validate that every redirect preserves the approved origin and HTTPS scheme. 8. Use narrowly scoped WooCommerce keys and separate read-only health-check credentials from write-capable publishing credentials. 9. Rotate any credentials that may previously have been used with HTTP or an untrusted endpoint. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/main.py:562
Finding
Caller-controlled output path allows arbitrary file overwrite<![CDATA[ ## Vulnerability Details **File Location**: `src/main.py:562-568`, `src/main.py:652-653` **Vulnerability Type**: Arbitrary filesystem write through an unrestricted output path **Risk Level**: High ### Vulnerable Code ```python def save_result(self, result: Dict, output_path: str = "output/result.json") -> None: """Save result to JSON file""" output_file = Path(output_path) output_file.parent.mkdir(parents=True, exist_ok=True) with open(output_file, "w", encoding="utf-8") as f: json.dump(result, f, indent=2, ensure_ascii=False) ``` The output path is taken directly from runtime JSON: ```python output_path = input_data.get("output", "output/result.json") automator.save_result(result, output_path) ``` ### Technical Analysis The code accepts an arbitrary path from JSON input and passes it directly to `Path` and `open(..., "w")`. It does not reject absolute paths, normalize and confine relative paths, prevent `..` traversal, check for symbolic links, or require explicit confirmation before replacing an existing file. Although `schemas/input_schema.json` declares `additionalProperties: false` and does not define an `output` property, the runtime does not validate input against that schema. The undeclared `output` field is therefore accepted. Opening the path with mode `"w"` truncates an existing file. `mkdir(parents=True)` also permits creation of attacker-selected directory trees wherever the process has permission. ### Attack Path 1. An attacker supplies workflow JSON containing an `output` property. 2. The property contains an absolute path or traversal sequence, such as `../../target.json`. 3. The runtime accepts the property because no schema validation is performed. 4. The workflow completes and calls `save_result()`. 5. Parent directories are created if possible. 6. The selected target is opened in write mode and truncated. 7. Generated JSON replaces the previous file contents. Exploitation is limited to paths writa ...[truncated 793 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce `schemas/input_schema.json` before processing runtime input. 2. Do not accept an output path from untrusted input unless the feature is necessary. 3. Resolve all output paths beneath a dedicated application-owned directory: ```python base = Path("output").resolve() candidate = (base / supplied_name).resolve() if base not in candidate.parents: raise ValueError("Output path escapes the output directory") ``` 4. Reject absolute paths, `..` path components, symbolic-link traversal, and special device paths. 5. Accept a filename rather than an unrestricted path and apply a strict character allowlist. 6. Use exclusive creation mode where replacement is unnecessary. 7. Require explicit overwrite authorization if the destination already exists. 8. Run the Skill under an account with minimal filesystem permissions. 9. Consider atomic writes through a safely created temporary file followed by a controlled rename. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/product_synthesizer.py:193
Finding
Unsanitized product input is published as storefront HTML<![CDATA[ ## Vulnerability Details **File Location**: `src/product_synthesizer.py:193-247`, `src/shopify.py:157-164`, `src/woocommerce.py:200-204` **Vulnerability Type**: Stored HTML injection through unescaped commerce content **Risk Level**: Medium ### Vulnerable Code The product name is interpolated directly into HTML: ```python description = f""" <h2>About This Product</h2> <p>Introducing our premium <strong>{product_name}</strong>, designed to exceed your expectations. Crafted with precision and attention to detail, this product offers exceptional value and performance.</p> <h2>Key Features</h2> <ul> <li>Premium quality materials</li> <li>Durable and long-lasting</li> <li>Modern design</li> <li>Easy to use</li> <li>Great value for money</li> </ul> <h2>Why Choose {product_name}?</h2> <p>Our {product_name} stands out from the competition with its superior build quality and thoughtful design. Whether you're a beginner or professional, this product is perfect for your needs.</p> <p><strong>Order now</strong> and experience the difference!</p> """ ``` The fallback-language branch has the same issue: ```python description = f""" <h2>{product_name}</h2> <p>Premium quality product with excellent features and great value.</p> <h3>Features:</h3> <ul> <li>High quality materials</li> <li>Durable construction</li> <li>Modern design</li> <li>Easy to use</li> </ul> <p>Order now!</p> """ ``` Shopify receives the unsanitized HTML: ```python product_data = { "product": { "title": title, "body_html": description, ``` WooCommerce also receives it directly: ```python product_data = { "name": title, "description": description, "short_description": short_description, ``` ### Technical Analysis `product_name` and caller-provided descriptions are treated as trusted HTML. The synthesizer inserts `product_name` into HTML templates without escaping special characters. In addition, when a caller supplies `description`, `synthesize()` uses ...[truncated 1787 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape `product_name`, category, vendor, tag, and other plain-text values before placing them into HTML. 2. Sanitize caller-provided and generated descriptions with a strict allowlist of necessary tags and attributes. 3. Remove scripts, event-handler attributes, unsafe URL schemes, inline styles, forms, embedded frames, and active media. 4. Validate links and images against an approved scheme and, where appropriate, an approved-domain policy. 5. Treat model-generated content as untrusted input and apply the same sanitizer. 6. Prefer structured product content and render HTML from trusted templates after escaping values. 7. Display a publication preview and require confirmation when content contains markup or external links. 8. Retain downstream platform sanitization as defense in depth rather than the primary control. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:6
Finding
Unpinned and unnecessary dependencies create supply-chain exposure<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:6-18`, `SKILL.md:86-89` **Vulnerability Type**: Non-reproducible third-party dependency installation **Risk Level**: Medium ### Vulnerable Code The documented installation command executes dependency installation: ```text pip install -r requirements.txt ``` All dependencies use open-ended lower bounds: ```text google-genai>=0.1.0 # Legacy package (for compatibility) google-generativeai>=0.8.0 # HTTP requests requests>=2.31.0 # Image processing (required for saving generated images) pillow>=10.0.0 # Optional: for async operations aiohttp>=3.9.0 ``` ### Technical Analysis The dependency file does not pin exact versions or provide package hashes. A clean installation may therefore select future package releases that were not reviewed with the Skill. This makes builds non-reproducible and increases exposure to compromised upstream releases, unexpected breaking changes, and newly introduced vulnerabilities. The audited source imports `google.genai`, `requests`, and Pillow. The listed legacy `google-generativeai` package and optional `aiohttp` package are not used by the inspected runtime code, unnecessarily expanding the dependency and transitive-dependency surface. No evidence was found that the currently named packages are typosquatted or intentionally malicious. The finding concerns unsafe dependency management rather than a confirmed malicious package. ### Attack Path 1. A user follows the installation instructions and runs `pip install -r requirements.txt`. 2. The package resolver selects the newest releases satisfying each lower-bound constraint. 3. A selected direct or transitive dependency may differ from the versions originally tested. 4. Package installation hooks or imported runtime code execute with the user's privileges. 5. A compromised or vulnerable future release can affect the Skill without any change to the audited repository. ### Impact Assessment Dependency in ...[truncated 557 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct dependency to a reviewed exact version. 2. Generate and commit a lock file containing hashes, such as a hash-locked `requirements.txt` produced by `pip-tools`. 3. Install with hash verification enabled. 4. Remove `google-generativeai` if legacy compatibility is not actually required. 5. Remove `aiohttp` unless asynchronous operations are implemented and used. 6. Review and pin transitive dependencies as part of release preparation. 7. Use automated vulnerability and dependency-update scanning. 8. Build dependencies in an isolated environment and run the Skill under a least-privileged account. 9. Periodically update pins through a controlled review and testing process rather than permitting unbounded upgrades. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (65)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is framed as content generation, yet it reportedly performs direct WooCommerce or WordPress API access and live store mutation. That discrepancy materially increases risk because users may authorize a content tool without realizing it can publish products or change stock in a production commerce system.

Credential Access

High
Category
Privilege Escalation
Content
- `GOOGLE_API_KEY` - Google API Key for Nano Banana 2 image generation
- `SHOPIFY_STORE_URL` - Shopify store URL
- `SHOPIFY_ACCESS_TOKEN` - Shopify Admin API access token
- `WOOCOMMERCE_STORE_URL` - WooCommerce store URL
- `WOOCOMMERCE_CONSUMER_KEY` - WooCommerce API consumer key
- `WOOCOMMERCE_CONSUMER_SECRET` - WooCommerce API consumer secret
Confidence
90% confidence
Finding
The skill requests and documents use of multiple high-privilege credentials, including store access tokens and API secrets, for networked operations against live commerce platforms. In this context, broad credential access is dangerous because compromise, misuse, or accidental invocation could lead to unauthorized publication, inventory changes, store reconnaissance, or leakage of business-sensitive data.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
}
            })

        return prompts

    def _generate_content_drafts(
        self,
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
}
            })

        return prompts

    def _generate_content_drafts(
        self,
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Credential Access

High
Category
Privilege Escalation
Content
Args:
            google_api_key: Google API Key for Nano Banana 2
            shopify_store_url: Shopify store URL
            shopify_access_token: Shopify Admin API access token
            woo_store_url: WooCommerce store URL
            woo_consumer_key: WooCommerce API consumer key
            woo_consumer_secret: WooCommerce API consumer secret
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Args:
            google_api_key: Google API Key for Nano Banana 2
            shopify_store_url: Shopify store URL
            shopify_access_token: Shopify Admin API access token
            woo_store_url: WooCommerce store URL
            woo_consumer_key: WooCommerce API consumer key
            woo_consumer_secret: WooCommerce API consumer secret
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Args:
            google_api_key: Google API Key for Nano Banana 2
            shopify_store_url: Shopify store URL
            shopify_access_token: Shopify Admin API access token
            woo_store_url: WooCommerce store URL
            woo_consumer_key: WooCommerce API consumer key
            woo_consumer_secret: WooCommerce API consumer secret
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
args = parser.parse_args()

    # Get API keys from environment if not provided
    google_api_key = args.api_key or os.environ.get("GOOGLE_API_KEY")
    shopify_url = args.shopify_url or os.environ.get("SHOPIFY_STORE_URL")
    shopify_token = args.shopify_token or os.environ.get("SHOPIFY_ACCESS_TOKEN")
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Args:
            store_url: Shopify store URL (e.g., "mystore.myshopify.com")
            access_token: Shopify Admin API access token
        """
        self.store_url = store_url or os.environ.get("SHOPIFY_STORE_URL", "")
        self.access_token = access_token or os.environ.get("SHOPIFY_ACCESS_TOKEN", "")
Confidence
87% confidence
Finding
The code is designed to access a Shopify Admin API token, which is a powerful credential for store management. Credential access is especially sensitive here because the skill description does not clearly prepare the user for privileged store operations, increasing the likelihood of misuse or overbroad deployment.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This code performs authenticated product creation in a live Shopify store, which materially exceeds the declared skill scope of generating visuals, product data, copy, and export-ready assets. In a skill context, undocumented write access to an external commerce platform is dangerous because it can alter production catalog state, publish unintended products, and create business impact without clear user expectation.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
This skill performs direct state-changing actions against a live WooCommerce store, including product creation and inventory updates, despite being framed as a content-generation and commerce-asset preparation tool. That mismatch is dangerous because users may authorize or invoke the skill expecting draft/export behavior, while the code can publish products and alter stock in production.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares access to sensitive environment variables and clearly describes networked publishing behavior, but it does not declare any explicit tool scope or allowed-tools policy. That creates an authorization gap where an agent may use broader capabilities than a reviewer or user expects, especially given the presence of store credentials and write-capable commerce workflows.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The quick-start example hard-codes `country="us"` and `language="en"`, which presents a default locale choice rather than asking the user to select one. Similar locale defaults recur in the documented API, and the file does not clearly state that users should be offered a language/locale choice first.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The API reference explicitly defines `country='us'` and `language='en'` as defaults for the main workflow. This is a natural-language policy concern because it bakes in a specific locale and language without indicating user consent, choice, or a justified regional limitation.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes a skill focused on generating visuals, structured product data, localized commerce copy, and export-ready commerce assets. This JSON additionally produces a multi-week social/media distribution strategy with channels, KPIs, timing guidance, and iteration planning, which is a broader marketing campaign planning function rather than a direct commerce asset generation detail.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
This JSON output includes a locale-setting field of "language": "en", which indicates the skill is forcing English output. The policy allows locale constraints only when the user is given a choice or when the restriction is clearly documented and justified, neither of which is present in this file.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The prompt instructs the system to produce a `generated_images` field as if actual image generation and file persistence will occur, which implicitly expands the skill from content generation into side-effecting execution. This is dangerous because downstream orchestrators may treat the prompt as authorization to invoke tools or write files without explicit manifest declaration, user consent, or policy checks.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The prompt explicitly states that the system will call Google AI Studio API, save generated images to local storage, and return file paths/URLs, introducing undeclared network access and local file writes. This creates a capability mismatch where an LLM prompt can socially engineer the host agent into performing sensitive side effects beyond the stated skill scope.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Automatic image generation and local storage are presented as silent default behavior with no user-facing warning or consent step. Hidden side effects are risky because users may provide inputs assuming text-only processing, while the system performs external API calls, incurs cost, transmits data off-box, or writes artifacts locally without transparency.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The schema description explicitly promises an end-to-end workflow including auto-publishing, while the skill metadata describes generation of visuals, product data, copy, and export-ready assets. This mismatch can cause downstream systems or users to authorize a capability they did not reasonably expect, increasing the risk of unintended store modifications or product publication without clear consent boundaries.

Static analysis

No suspicious patterns detected.