Back to skill

Security audit

Bot-to-Bot Arbitrage Framework: Multi-Bot Coordination with Trust Verification

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed educational arbitrage guide, but its sample framework handles financial settlement and sensitive trading signals with material confidentiality and verification gaps.

Review this skill carefully before installing or using it for real trading. Treat the code as an educational draft only: add recipient-scoped or encrypted event delivery, verify reporter identities and signatures before settlement, avoid raw exported signing keys, and test only in paper-trading or sandbox environments until the financial controls are independently reviewed.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:884
Finding
Unsigned and Unauthorized Fill Reports Can Be Accepted as Verified Execution## Vulnerability Details **File Location**: `SKILL.md`, lines 884-927 **Vulnerability Type**: Missing cryptographic verification and authorization **Risk Level**: High ### Vulnerable Code ```python for event in events.get("events", []): report = event["payload"] exchange = report["exchange"] if exchange in verified_legs: continue # already verified this leg # Find the expected leg for this exchange expected = next( (l for l in expected_legs if l["exchange"] == exchange), None ) if not expected: continue # Validate fill against expectations validation = self._validate_fill(report, expected) if validation["valid"]: verified_legs[exchange] = { "report": report, "validation": validation } else: failures.append({ "exchange": exchange, "reason": validation["reason"], "report": report }) if len(verified_legs) < len(expected_legs): time.sleep(0.5) all_verified = len(verified_legs) == len(expected_legs) verification = { "opportunity_id": opportunity_id, "all_verified": all_verified, "verified_legs": verified_legs, "failures": failures, "missing_legs": [ l["exchange"] for l in expected_legs if l["exchange"] not in verified_legs ], "verified_at": datetime.utcnow().isoformat() } ``` ### Technical Analysis The verifier accepts an event based only on its claimed exchange and whether its reported price and quantity fall within expected tolerances. It does not: - Verify the Ed25519 signature embedded in the report. - Confirm that `reporter_id` is the bot authorized by the negotiated deal. - Bind the reporting agent to the claimed exchange. - Confirm that the event originated from the authenticated reporting agent. - Reject replayed fill reports or d ...[truncated 1707 chars]
Remediation
## Remediation Suggestions - Obtain the authorized bot identity and public key from the negotiated deal rather than trusting fields supplied by the report. - Reconstruct the exact canonical unsigned payload and verify its Ed25519 signature before processing the report. - Require `reporter_id` to match the bot assigned to the expected exchange and opportunity. - Verify that the authenticated event publisher matches `reporter_id`. - Bind each expected leg to a unique deal ID, bot ID, exchange, order nonce, and opportunity ID. - Maintain a replay cache for signatures, nonces, event IDs, and exchange order IDs. - Reject malformed, duplicate, expired, or out-of-window reports. - Where supported, validate exchange-generated execution receipts through an independent exchange API or signed exchange attestation. - Do not build settlement evidence or release escrow unless every leg passes authentication, authorization, freshness, and semantic validation. - Add negative tests covering forged signatures, mismatched reporters, replayed reports, and reports from unassigned exchanges.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:347
Finding
Execution Signals Are Published Without Explicit Recipient Restrictions## Vulnerability Details **File Location**: `SKILL.md`, lines 347-351 **Vulnerability Type**: Sensitive trading-data exposure through insufficient event access control **Risk Level**: High ### Vulnerable Code ```python execute("publish_event", { "agent_id": self.agent_id, "event_type": "arbitrage.execution_signal", "payload": signal }) ``` The transmitted `signal` contains sensitive execution information: ```python signal = { "opportunity_id": opportunity_id, "exchange": leg["exchange"], "side": leg["side"], "symbol": leg["symbol"], "quantity": leg["quantity"], "limit_price": leg["limit_price"], "execution_deadline_ms": leg.get("deadline_ms", 500), "escrow_id": self.pending_escrows.get(opportunity_id), "timestamp": datetime.utcnow().isoformat() } signal["signature"] = self.sign_payload(signal) ``` ### Technical Analysis The principal `dispatch_execution()` implementation publishes each order signal without a `visibility` allowlist, recipient identifier, or encrypted payload. The signal discloses the target exchange, side, asset, quantity, price, deadline, active opportunity ID, and escrow ID. A later section of the guide demonstrates scoped events, but that safeguard is not applied to the main coordinator implementation. If the event service defaults to public, tenant-wide, or otherwise broad visibility, parties other than the selected exchange bot can observe imminent trades. Signing the signal provides authenticity but no confidentiality. Any event consumer that can read the payload can obtain the trading intent. ### Attack Path 1. An attacker gains legitimate or unintended read access to the event stream. 2. The coordinator publishes an execution signal without a recipient allowlist. 3. The attacker extracts the exchange, side, symbol, quantity, limit price, and deadline. 4. The attacker submits a competing order before the intended ...[truncated 815 chars]
Remediation
## Remediation Suggestions - Require an explicit recipient allowlist for every execution signal, limited to the bot assigned to that specific leg. - Make signal dispatch fail closed when recipient scoping is absent or unsupported. - Encrypt each payload with authenticated public-key encryption for the selected bot. - Include the recipient identity, deal ID, opportunity ID, leg ID, expiration time, and nonce in the signed and encrypted data. - Send each bot only its own leg; never disclose the complete arbitrage opportunity. - Exclude escrow identifiers unless they are strictly required by the executor. - Use short expiration windows and replay protection. - Confirm the event service’s default visibility and tenant-isolation behavior instead of assuming privacy. - Add integration tests proving that unrelated agents cannot query or subscribe to execution signals. - Document metadata and event payloads that are visible to the GreenHelix service operator.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:1483
Finding
Counterparty Reveal Publishes the Full Opportunity in Plaintext## Vulnerability Details **File Location**: `SKILL.md`, lines 1483-1513 **Vulnerability Type**: Misleading confidentiality control and plaintext sensitive-data transmission **Risk Level**: High ### Vulnerable Code ```python def reveal_to_counterparty( self, opportunity_id: str, counterparty_public_key_b64: str ) -> dict: """Reveal opportunity details to a specific counterparty. In production, this would encrypt the details with the counterparty's public key. For this example, we publish a reveal event that references the original commitment. """ stored = self.commitments.get(opportunity_id) if not stored: raise ValueError(f"No commitment found for {opportunity_id}") reveal_payload = { "opportunity_id": opportunity_id, "preimage": stored["preimage"], "commitment": stored["commitment"], "revealed_to": counterparty_public_key_b64, "revealed_at": datetime.utcnow().isoformat() } # Counterparty can verify: sha256(preimage) == commitment execute("publish_event", { "agent_id": self.agent_id, "event_type": "arbitrage.opportunity_reveal", "payload": reveal_payload, "signature": self.sign_payload(reveal_payload) }) return reveal_payload ``` ### Technical Analysis The method accepts a counterparty public key but does not use it for encryption. Instead, it places the key in the `revealed_to` metadata field and publishes the complete commitment preimage as plaintext. The preimage includes: - Symbol. - Buy and sell exchanges. - Buy and sell prices. - Quantity. - Opportunity identifier. - Commitment nonce. The publication call also omits an explicit event visibility restriction. Therefore, the implementation does not provide the confidentiality implied by `reveal_to_counterparty()` or by the surrounding MEV-protection discussion. The co ...[truncated 1317 chars]
Remediation
## Remediation Suggestions - Do not publish the plaintext preimage. - Use an authenticated key-agreement and encryption scheme appropriate to the counterparty’s registered encryption key. - Do not assume an Ed25519 signing key can directly serve as an encryption key; register and validate a suitable encryption key or use a documented conversion protocol with expert review. - Encrypt the preimage locally and publish only ciphertext, nonce, algorithm identifiers, recipient ID, and necessary authenticated metadata. - Apply an explicit recipient allowlist in addition to encryption. - Authenticate the counterparty key against its registered agent identity and negotiated deal. - Include deal ID, recipient ID, expiration, and opportunity ID as authenticated associated data. - Rotate or expire reveals rapidly and reject replayed ciphertexts. - Rename or remove the method until genuine recipient confidentiality is implemented. - Add tests demonstrating that unauthorized subscribers and the event transport cannot recover plaintext opportunity details.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:427
Finding
Coordinator Private Key Is Exported as an Unencrypted Base64 String## Vulnerability Details **File Location**: `SKILL.md`, lines 427-440 **Vulnerability Type**: Unsafe cryptographic key handling **Risk Level**: Medium ### Vulnerable Code ```python private_key = Ed25519PrivateKey.generate() public_key = private_key.public_key() private_bytes = private_key.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption() ) public_bytes = public_key.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw ) COORDINATOR_PRIVATE_KEY = base64.b64encode(private_bytes).decode() ``` ### Technical Analysis The coordinator private key is explicitly exported in raw form with `NoEncryption()` and converted into an ordinary immutable Python string. Base64 is an encoding, not encryption, and offers no protection against disclosure. The example retains the key in several runtime objects: the cryptographic key object, `private_bytes`, and `COORDINATOR_PRIVATE_KEY`. A string is particularly prone to accidental exposure through debug output, exception reporting, configuration serialization, process inspection, notebook state, or logging. The audited code does not print or transmit `COORDINATOR_PRIVATE_KEY`. Therefore, the pre-scan warning about direct key exfiltration is not confirmed. Likewise, `base64.b64decode()` is used to reconstruct an Ed25519 key object and does not execute decoded code. The confirmed issue is unsafe secret representation and lifecycle management. ### Attack Path 1. The example generates and exports the raw private key without encryption. 2. The key is retained as a reusable base64 string and passed among several classes. 3. Application logging, debugging, state serialization, a crash report, or runtime inspection exposes the string. 4. An attacker decodes the base64 value to recover the raw Ed25519 private key. 5. The attacker sign ...[truncated 782 chars]
Remediation
## Remediation Suggestions - Keep the private key in a non-exportable HSM, KMS, operating-system key store, or dedicated secrets manager where possible. - If export is unavoidable, store it in an encrypted private-key format protected by a separately managed secret. - Avoid global base64 private-key strings and minimize the number of in-memory copies. - Load `AGENT_SIGNING_KEY` through a secure secret-injection mechanism rather than embedding or serializing it in application state. - Pass a signer interface or protected key object to components instead of raw private-key material. - Never include private keys in logs, exceptions, metrics, event payloads, notebooks, or compliance reports. - Restrict process and secret-store access to the minimum runtime identity. - Implement key rotation and immediate revocation procedures. - Zero mutable key buffers where the language and cryptographic library permit it. - Add automated secret-scanning and logging tests to prevent accidental output of key values.
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 (9)

External Transmission

Medium
Category
Data Exfiltration
Content
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization

API_BASE = "https://api.greenhelix.net/v1"
API_KEY = "your-api-key"

session = requests.Session()
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization

API_BASE = "https://api.greenhelix.net/v1"
API_KEY = "your-api-key"

session = requests.Session()
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The coordinator documentation says each bot should receive only its own leg, but `dispatch_execution` publishes raw execution signals without any visibility scoping. In a multi-bot arbitrage setting, exposing leg details broadly defeats the stated information-barrier design and can leak actionable trade intent that enables copy-trading or front-running.

External Transmission

Medium
Category
Data Exfiltration
Content
}
```

The equivalent curl for bot discovery:

```bash
# Discover Binance specialist bots
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"Failures: {verification['failures']}")
```

The curl equivalent for building evidence:

```bash
# Build claim chain for execution proof
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
}
```

### Settlement via curl

```bash
# Release escrow after verified execution
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The guide claims reveals should be private or encrypted, but the sample `reveal_to_counterparty` implementation publishes the full opportunity preimage to the event bus. That leaks both legs, prices, quantity, and timing data, enabling counterparties or observers to reconstruct and potentially front-run the arbitrage despite the surrounding MEV-protection claims.

External Transmission

Medium
Category
Data Exfiltration
Content
```

```bash
curl -X POST https://sandbox.greenhelix.net/v1 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```

```bash
curl -X POST https://sandbox.greenhelix.net/v1 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.