Back to skill

Security audit

The Multi-Agent Commerce Cookbook: Orchestrating Agent Teams That Discover, Negotiate, Pay, and Verify Each Other

Security checks for vulnerabilities and agentic risk

Overview

This non-executing guide is broadly aligned with agent commerce, but it requests powerful credentials and includes copy-paste patterns that can automatically create, release, dispute, or refund payments.

Review before installing. Use sandbox credentials first, avoid exposing Stripe or signing keys unless a specific workflow needs them, replace returned private-key strings with a secrets-manager reference, and add explicit approval, strict budget caps, and authenticated triggers before letting agents move funds automatically.

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

Unused High-Value Credentials Violate Least-Privilege Requirements

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 14-22
Vulnerability Type: Excessive credential exposure
Risk Level: Medium

Vulnerable Code

yaml
credentials: [GREENHELIX_API_KEY, AGENT_SIGNING_KEY, STRIPE_API_KEY]
metadata:
  openclaw:
    requires:
      env:
        - GREENHELIX_API_KEY
        - AGENT_SIGNING_KEY
        - STRIPE_API_KEY
    primaryEnv: GREENHELIX_API_KEY

Technical Analysis

The Skill declares AGENT_SIGNING_KEY and STRIPE_API_KEY as required environment credentials even though the reviewed examples do not read or use either variable. The demonstrated network client only reads GREENHELIX_API_KEY.

Requiring unrelated signing and payment credentials violates the principle of least privilege. If the hosting platform exposes every declared variable to the agent or Skill execution context, sensitive credentials become accessible despite not being necessary for the documented functionality.

This issue is especially significant because a signing key can authorize actions under an agent identity, while a Stripe API key may permit payment operations according to its account-level scope. The unnecessary exposure increases the consequences of prompt injection, compromised tools, accidental logging, debugging output, or another flaw in the surrounding agent environment.

Attack Path

  1. A user installs or loads the Skill.
  2. The hosting platform processes the metadata and requests or injects all three declared credentials.
  3. AGENT_SIGNING_KEY and STRIPE_API_KEY enter the Skill or agent environment even though the examples do not require them.
  4. A compromised agent, unsafe tool, malicious prompt, debugging facility, or unrelated integration reads the unnecessary environment variables.
  5. The exposed credentials are used outside the intended GreenHelix guide workflow.

Impact Assessment

Successful exploitation could disclose an agent signing k ...[truncated 415 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove AGENT_SIGNING_KEY and STRIPE_API_KEY from the top-level credentials and requires.env declarations unless a concrete example actually consumes them.
  • Declare credentials separately for each optional workflow instead of exposing every secret whenever the Skill is loaded.
  • Request GREENHELIX_API_KEY only when a user explicitly chooses to run a GreenHelix example.
  • Use narrowly scoped, revocable credentials restricted to the minimum required API operations.
  • Keep production credentials out of educational and sandbox workflows; use dedicated sandbox credentials and fake funds for tests.
  • Document the exact permission scope required for each optional integration.
  • Ensure the host does not automatically make all declared secrets available to model context, logs, unrelated tools, or subprocesses.
  • Add automated metadata validation that rejects declared credentials not referenced by any corresponding implementation.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:153
Finding

Unencrypted Ed25519 Private Keys Are Returned in General Application State

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 153-169 and 199-216
Vulnerability Type: Plaintext sensitive-key handling
Risk Level: Medium

Vulnerable Code

python
def generate_keypair() -> tuple[str, str]:
    """Generate an Ed25519 keypair. Returns (private_b64, public_b64)."""
    private_key = Ed25519PrivateKey.generate()
    public_key = private_key.public_key()
    priv_b64 = base64.b64encode(
        private_key.private_bytes(
            serialization.Encoding.Raw,
            serialization.PrivateFormat.Raw,
            serialization.NoEncryption(),
        )
    ).decode()
    pub_b64 = base64.b64encode(
        public_key.public_bytes(
            serialization.Encoding.Raw,
            serialization.PublicFormat.Raw,
        )
    ).decode()
    return priv_b64, pub_b64
python
        # Generate identity
        private_key, public_key = generate_keypair()

        # Register on the gateway
        reg_result = execute("register_agent", {
            "agent_id": agent_id,
            "public_key": public_key,
            "name": name,
        })

        # Create isolated wallet
        wallet_result = execute("create_wallet", {})

        # Fund the wallet
        deposit_result = execute("deposit", {"amount": str(budget)})

        crew[agent_id] = {
            "public_key": public_key,
            "private_key": private_key,  # Store in secrets manager
            "registration": reg_result,
            "wallet": wallet_result,
            "deposit": deposit_result,
        }

Technical Analysis

The private Ed25519 key is serialized with serialization.NoEncryption(), Base64-encoded, and returned as a normal string. Base64 only changes the representation of the key; it does not provide confidentiality or access control.

The provisioning function then places the plaintext-equivalent private key in the ret ...[truncated 2039 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not return private-key material from generate_keypair() or provision_crew() as a string.
  • Store newly generated private keys immediately in a dedicated secrets manager, hardware security module, operating-system keychain, or hardware-backed keystore.
  • Return only the public key and an opaque key identifier or secrets-manager reference.
  • Prefer non-exportable private keys where the selected cryptographic backend supports them.
  • If key export is unavoidable, encrypt the serialized key using an authenticated encryption mechanism and a separately managed key-encryption key.
  • Prevent sensitive values from appearing in object representations, logs, traces, exception reports, telemetry, caches, and inter-agent messages.
  • Separate public provisioning results from private cryptographic state rather than combining them in one dictionary.
  • Apply strict access controls, rotation procedures, and revocation or identity-recovery mechanisms.
  • Replace the misleading comment with executable secrets-manager integration so copied example code is secure by default.
  • Add tests that verify returned provisioning objects never contain private-key bytes or encoded private-key strings.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Unvalidated Output Injection

High
Category
Output Handling
Confidence
85% confidence
Finding

Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Content

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

md
"escrow_id": escrow_id,
        }]
    else:
        dispute = execute("open_dispute", {
            "escrow_id": escrow_id,
            "reason": f"Phase {phase_name}: output quality below threshold",
        })

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 132)May include surrounding context.

md
import base64

API_KEY = os.environ["GREENHELIX_API_KEY"]
BASE_URL = "https://api.greenhelix.net/v1"

session = requests.Session()
session.headers.update({

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The example places each agent's private signing key into the returned in-memory crew object, increasing the chance that downstream code logs, serializes, or transmits the key accidentally. In a multi-agent commerce context, compromise of an Ed25519 signing key can enable agent impersonation and unauthorized transaction signing.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.