Back to skill

Security audit

Locking Down Agent Commerce: The OWASP-Aligned Security Guide for Autonomous AI Agents on GreenHelix

Security checks for vulnerabilities and agentic risk

Overview

This non-executable guide is mostly purpose-aligned, but its copy-paste code can touch live financial APIs and includes unsafe fail-open security examples.

Review this skill carefully before using its examples with real credentials or funds. Treat the code as educational, not production-ready: use sandbox credentials, replace active permission probing with read-only capability introspection, make escrow verification mandatory, keep private keys in a signer/KMS or secret manager, and require explicit human approval for key revocation or high-value payment actions.

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
SKILL.md:183
Finding

Permission assessment invokes potentially state-changing tools without dry-run enforcement

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 183-200
Vulnerability Type: Unsafe authorization probing through mutating API calls
Risk Level: High

Vulnerable Code

python
def probe_tool_access(self) -> dict:
    """Test which tool categories this agent can access."""
    accessible = {}
    for category, tools in self.TOOL_CATEGORIES.items():
        category_tools = []
        for tool in tools:
            try:
                # Dry-run with minimal input to test access
                self._execute(tool, {"agent_id": self.agent_id})
                category_tools.append(tool)
            except requests.exceptions.HTTPError as e:
                if e.response.status_code == 403:
                    pass  # No access -- expected for restricted tools
                elif e.response.status_code in (400, 422):
                    category_tools.append(tool)  # Accessible but bad input
                # 5xx = service issue, not a permission problem
        accessible[category] = category_tools
    return accessible

Technical Analysis

The method attempts to discover tool permissions by invoking every tool through the ordinary execution endpoint. The associated tool catalog includes mutating and financially sensitive operations such as deposit, create_wallet, create_escrow, release_escrow, send_message, and resolve_dispute.

The comment labels these requests as dry runs, but neither the request nor _execute() supplies a dry-run flag. There is also no evidence of a server-enforced simulation mode. The code assumes that minimal input will always produce a validation error before side effects occur. That assumption is unsafe because some endpoints may accept agent_id as sufficient input, apply defaults, partially mutate state before validation, or change their validation requirements in a later API version.

This permission assessment therefore exceeds the minimum read-only privileges necessary to inve ...[truncated 1595 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace active probing with a dedicated read-only authorization or capability-introspection endpoint.
  2. Never invoke financial, identity-write, messaging, dispute-resolution, key-management, or other mutating tools to determine whether access exists.
  3. If the platform supports simulation, require an explicit server-enforced dry-run flag and verify that every probed endpoint guarantees transactional rollback.
  4. Maintain an allowlist of demonstrably read-only tools if introspection is unavailable.
  5. Use a dedicated sandbox account and a minimally scoped assessment credential rather than a production or administrative key.
  6. Require explicit operator confirmation before any active probe and clearly list every endpoint that will be contacted.
  7. Add automated tests that fail if a mutating tool is added to the probe allowlist.
  8. Treat ambiguous responses, timeouts, and server errors as an unknown permission state rather than evidence that access is available.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:1054
Finding

Secure escrow wrapper permits release without deliverable verification

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 1054-1075
Vulnerability Type: Fail-open authorization for financial release
Risk Level: High

Vulnerable Code

python
def release_escrow(
    self,
    escrow_id: str,
    verification_fn: Optional[callable] = None,
) -> dict:
    """Release escrow only after deliverable verification.

    If verification_fn is provided, it is called with the escrow_id
    and must return True for the release to proceed. This prevents
    agents from releasing funds without verifying the deliverable.
    """
    if verification_fn is not None:
        if not verification_fn(escrow_id):
            raise SecurityError(
                f"Deliverable verification failed for escrow {escrow_id}. "
                f"Release blocked."
            )

    return self.agent._execute("release_escrow", {
        "escrow_id": escrow_id,
    })

Technical Analysis

The method is documented as releasing escrow only after deliverable verification, but its verification callback is optional. When verification_fn is omitted or passed as None, the method immediately invokes release_escrow.

This creates a fail-open security boundary: the absence of a verifier is treated as authorization to release funds rather than as an error. A simple caller mistake, incomplete integration, or manipulated tool call can therefore bypass the control that the wrapper claims to enforce.

The method also does not independently verify that:

  • The escrow belongs to the current payer.

  • The expected payee and amount match locally approved values.

  • The escrow is in a releasable state.

  • A human or policy engine approved a high-value release.

  • The verification result is fresh, bound to the escrow, and resistant to replay.

    Attack Path

  1. An attacker places adversarial instructions in a marketplace listing, message, or deliverable processed by an autonomous commerce agent.
  2. The attacker induces the agent or its t ...[truncated 1135 chars]
Remediation
View remediation

Remediation Suggestions

  1. Make verification mandatory by removing the default value and rejecting a missing verifier:
python
if verification_fn is None:
    raise SecurityError("Deliverable verification is required.")
  1. Prefer a structured, signed verification result over an arbitrary callback. Bind it cryptographically to the escrow ID, deliverable hash, payer, payee, amount, timestamp, and expiration.
  2. Fetch the escrow before release and verify its payer, payee, amount, currency, status, and expected local authorization record.
  3. Require explicit human approval or multi-party authorization for releases above a configurable value threshold.
  4. Use a narrowly scoped API key that can release only escrows owned by the relevant payer.
  5. Record the verification evidence and authorization decision in an append-only audit log before submitting the release.
  6. Add replay protection and require freshness for verification evidence.
  7. Add negative tests proving that missing, false, stale, mismatched, or exception-raising verification always blocks release.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The mutual verification example claims both parties prove private-key control, but the code never verifies a returned signature and unconditionally returns True. This creates a false sense of authentication, allowing escrow or payment flows to proceed without actually confirming the seller controls the registered identity, undermining the zero-trust model described by the guide.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The guide explicitly recommends key isolation, but the final wiring example loads AGENT_PRIVATE_KEY_B64 from an environment variable and passes the raw private key into the application process. In a commerce agent handling real money, this materially increases key-exposure risk through process memory, logs, crash dumps, /proc inspection, or prompt-injection-assisted local file/env disclosure if the runtime is compromised.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 165)May include surrounding context.

md
}

    def __init__(self, api_key: str, agent_id: str,
                 base_url: str = "https://api.greenhelix.net/v1"):
        self.api_key = api_key
        self.agent_id = agent_id
        self.base_url = base_url

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 305)May include surrounding context.

md
}

    def __init__(self, api_key: str, agent_id: str,
                 base_url: str = "https://api.greenhelix.net/v1"):
        self.api_key = api_key
        self.agent_id = agent_id
        self.base_url = base_url

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 1503)May include surrounding context.

md
}

    def __init__(self, api_key: str, agent_id: str,
                 base_url: str = "https://api.greenhelix.net/v1"):
        self.api_key = api_key
        self.agent_id = agent_id
        self.base_url = base_url

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 2159)May include surrounding context.

md
}

    def __init__(self, api_key: str, agent_id: str,
                 base_url: str = "https://api.greenhelix.net/v1"):
        self.api_key = api_key
        self.agent_id = agent_id
        self.base_url = base_url

Static analysis

No suspicious patterns detected.