Back to skill

Security audit

Agent Contract Lifecycle Management

Security checks for vulnerabilities and agentic risk

Overview

This non-executing guide is openly about contract automation, but its production-style examples can automate escrow, penalties, reputation actions, and termination with insufficient safeguards.

Review carefully before installing or adapting this skill. Treat it as illustrative only, use sandbox credentials, add explicit approval thresholds for any fund movement or termination, require bilateral signature verification before escrow funding, add idempotency and breach deduplication, and validate API destinations before sending bearer tokens.

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:1770
Finding
Escrow Funding Proceeds Without Verified Bilateral Signatures## Vulnerability Details **File Location**: `SKILL.md`, lines 1770-1790 **Vulnerability Type**: Missing authorization and signature verification before financial commitment **Risk Level**: High ### Vulnerable Code ```python def finalize_contract(self, contract: dict) -> dict: """Sign and activate a negotiated contract.""" # Sign the contract signature = self.signer.sign_contract(contract) contract["parties"]["consumer" if self.agent_id == contract["parties"]["consumer"]["agent_id"] else "provider"]["claim_chain_id"] = signature["claim_chain_id"] contract["parties"]["consumer" if self.agent_id == contract["parties"]["consumer"]["agent_id"] else "provider"]["signed_at"] = signature["signed_at"] # Create escrow escrow_result = self.escrow_mgr.create_contract_escrow(contract) escrow_id = escrow_result["escrow_id"] contract["escrow"]["escrow_id"] = escrow_id # Activate all SLA monitors activation = self.tracker.activate_all_obligations(contract) # Update fingerprint with all runtime IDs contract["fingerprint"] = self.signer.fingerprint(contract) ``` ### Technical Analysis The lifecycle manager signs the contract only as the currently authenticated agent and then immediately creates the escrow. It does not invoke `verify_counterparty_signature()`, even though that method is defined elsewhere in the guide for bilateral signature verification. Consequently, there is no enforcement that: - The counterparty signed the contract. - The counterparty signature belongs to the expected agent. - Both parties signed the same canonical contract fingerprint. - The counterparty signature was created before escrow funding. - The contract remained unchanged between signing and activation. The contract is also mutated after the local signature is generated by adding signature, escrow, and runtime identifiers. This requires a cle ...[truncated 1546 chars]
Remediation
## Remediation Suggestions 1. Define an immutable canonical contract payload that excludes mutable runtime fields such as escrow IDs and SLA monitor IDs. 2. Calculate one canonical fingerprint from that payload. 3. Require independent signatures from both expected party identities over that exact fingerprint. 4. Call `verify_counterparty_signature()` and verify the chain owner, contract ID, fingerprint, signature status, and expected counterparty identity before creating escrow. 5. Reject activation if either signature is absent, expired, revoked, malformed, or associated with another contract version. 6. Bind escrow creation to the verified fingerprint and signature-chain identifiers. 7. Add an explicit contract state machine such as `draft → locally_signed → bilaterally_signed → funded → active`. 8. Require a human or policy-engine approval for deposits above a configured financial threshold. 9. Use an idempotency key based on the contract ID and signed fingerprint to prevent duplicate escrow creation.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:1863
Finding
Milestone Processing Releases Gross Escrow Funds Before Applying Penalties## Vulnerability Details **File Location**: `SKILL.md`, lines 1863-1900; related release implementation at lines 677-717 **Vulnerability Type**: Incorrect financial transaction ordering and missing compliance gate **Risk Level**: High ### Vulnerable Code ```python def process_milestone(self, contract_id: str, milestone: str) -> dict: """Process a contract milestone, adjusting release for penalties.""" contract = self.contracts[contract_id] escrow_id = self.escrows[contract_id] # Calculate total penalties since last milestone relevant_penalties = [ e for e in self.enforcement_log if e.get("obligation_id") in [ o["obligation_id"] for o in contract["obligations"] ] ] total_penalties = sum( e.get("penalty_amount", 0) for e in relevant_penalties ) # Release milestone (amount will be adjusted by penalties) result = self.escrow_mgr.release_milestone( contract, escrow_id, milestone ) if result["released"]: adjusted_amount = max(0, result["amount"] - total_penalties) self._audit("milestone_processed", { "contract_id": contract_id, "milestone": milestone, "gross_release": result["amount"], "penalty_deductions": total_penalties, "net_release": adjusted_amount, }) return { "milestone": milestone, "result": result, "penalties_applied": total_penalties, } ``` The called helper releases the gross scheduled amount: ```python release_amount = round(total * (release_pct / 100.0), 2) result = self.execute("release_escrow", { "escrow_id": escrow_id, "agent_id": contract["parties"]["consumer"]["agent_id"], "amount": str(release_amount), }) ``` ### Technical Analysis `process_milestone()` calculates penalties but calls `release_m ...[truncated 2223 chars]
Remediation
## Remediation Suggestions 1. Fetch and verify the current compliance state before any milestone release. 2. Reject or suspend release if required obligations are noncompliant, unavailable, disputed, or still within an unresolved measurement window. 3. Calculate gross amount, applicable penalties, prior deductions, and net amount before invoking `release_escrow`. 4. Send only the final net amount to the escrow API. 5. Perform compliance verification, penalty consumption, and release as one atomic server-side operation where possible. 6. Associate every penalty with a contract ID, breach ID, accounting period, status, and target milestone. 7. Mark penalties as consumed only after a successful release transaction. 8. Persist milestone states and use idempotency keys to prevent repeated processing. 9. Reconcile the returned remote transaction amount against the requested net amount before writing the success audit event. 10. Ensure audit records contain the actual escrow transaction identifier and executed amount rather than a locally calculated value alone.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:1810
Finding
Recurring Monitoring Reapplies Penalties for the Same Unresolved Breach## Vulnerability Details **File Location**: `SKILL.md`, lines 1810-1843; enforcement implementation at lines 1089-1128 **Vulnerability Type**: Missing idempotency and breach-event deduplication **Risk Level**: High ### Vulnerable Code ```python # Check for breaches and enforce enforcement_actions = [] for obl_status in snapshot["obligations"]: if not obl_status["compliant"]: breach_data = { "actual_value": obl_status.get("current_value"), "threshold": obl_status["threshold"], "obligation_id": obl_status["obligation_id"], "detected_at": datetime.now(timezone.utc).isoformat(), "violation_count": 1, "breach_days": 1, } result = self.enforcer.enforce_breach( contract, obl_status["obligation_id"], breach_data, escrow_id ) if result["enforced"]: enforcement_actions.append(result) self.enforcement_log.append(result) ``` Each invocation then executes another penalty and reputation update: ```python enforcement_result = self._execute_penalty( contract, penalty_amount, escrow_id, obligation_id, breach_data ) self._record_enforcement( contract, obligation_id, penalty_amount, breach_data, enforcement_result ) ``` ### Technical Analysis The monitoring method is intended to run repeatedly, such as every five minutes. However, each observation of a noncompliant state is treated as a new breach with newly generated `detected_at`, `violation_count = 1`, and `breach_days = 1`. There is no mechanism to distinguish: - A newly started breach from an already open breach. - Multiple observations belonging to the same measurement window. - A continuing breach from a resolved and subsequently recurring breach. - A penalty already enforced for the same breach event. - A retry after an uncertain network response from a g ...[truncated 1589 chars]
Remediation
## Remediation Suggestions 1. Model breaches as persistent events with stable identifiers. 2. Derive an idempotency key from the contract ID, obligation ID, measurement window, and breach sequence. 3. Maintain explicit states such as `detected`, `grace_period`, `enforced`, `resolved`, and `reopened`. 4. Enforce only on valid state transitions or once per contract-defined accounting period. 5. Store remote transaction IDs and reject duplicate enforcement attempts. 6. Distinguish network retries from new enforcement operations using the same idempotency key. 7. Apply contract-defined grace periods, caps, and rolling-window rules before enforcement. 8. Submit reputation updates only after confirmed, deduplicated enforcement. 9. Prevent duplicate disputes by associating one active dispute with each unresolved breach event. 10. Add tests covering repeated monitoring of one continuous breach, recovery and recurrence, delayed API responses, and process restarts.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:125
Finding
Unrestricted API Base URL Can Expose Bearer Credentials## Vulnerability Details **File Location**: `SKILL.md`, lines 125-143 **Vulnerability Type**: Credential disclosure through attacker-controlled network destination **Risk Level**: High ### Vulnerable Code ```python 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 self.session = requests.Session() self.session.headers.update({ "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", }) def execute(self, tool: str, input_data: dict) -> dict: """Execute a GreenHelix tool and return the response.""" resp = self.session.post( f"{self.base_url}/v1", json={"tool": tool, "input": input_data}, ) resp.raise_for_status() return resp.json() ``` ### Technical Analysis The client accepts an arbitrary `base_url` and attaches the bearer credential to every request made by the session. It does not enforce HTTPS, validate the destination hostname, restrict ports, or bind the credential to an approved origin. If an attacker can influence configuration, constructor parameters, an agent-generated URL, or an integration wrapper, the client will transmit the authorization header to the selected endpoint. The `requests` library also follows redirects by default, and the implementation does not define a redirect policy. The request lacks an explicit timeout. A malicious or unavailable endpoint can therefore stall an autonomous workflow for an extended period, although timeout behavior may also depend on the surrounding runtime. ### Attack Path 1. An attacker gains influence over the `base_url` supplied to `ContractClient` or one of its subclasses. 2. The attacker provides a URL under their control, or a URL that redirects in an unsafe manner. 3. The client creates a session with the producti ...[truncated 970 chars]
Remediation
## Remediation Suggestions 1. Use a fixed production API origin or an explicit allowlist of approved HTTPS hostnames. 2. Parse and validate the URL before creating the client. 3. Reject HTTP, embedded user information, unexpected ports, fragments, and unapproved IP-literal destinations. 4. Resolve and validate destinations against private, loopback, link-local, and metadata-service address ranges where user-controlled URLs are possible. 5. Disable redirects for authenticated API requests or validate every redirect destination before forwarding credentials. 6. Attach the authorization header per request only after destination validation rather than placing it in unrestricted session defaults. 7. Set explicit connection and read timeouts, for example `timeout=(5, 30)`. 8. Use narrowly scoped, short-lived credentials with financial limits and rotation support. 9. Keep sandbox and production credentials separate. 10. Correct and normalize API path construction so a configured `/v1` base is not unintentionally combined with another `/v1`.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (8)

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The guide repeatedly claims escrow release is conditioned on verified SLA compliance, but the implementation releases milestone funds solely based on milestone name and percentage. This creates a dangerous integrity gap: operators may trust the example as enforcing compliance when it can pay out despite breaches, undermining financial controls and enabling loss of escrowed funds.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This markdown file states that agents can transfer deposits, automate penalty enforcement, escrow clawback, termination, and run workflows 'without human intervention.' Although it notes the guide is educational and uses a sandbox, it does not clearly warn readers that the described patterns involve financial commitments, automated settlements, and potentially destructive contract actions if adapted outside the sandbox.

External Transmission

Medium
Category
Data Exfiltration
Content
"""Base client for all contract lifecycle operations on GreenHelix."""

    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
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
"""Base client for all contract lifecycle operations on GreenHelix."""

    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
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
"""Base client for all contract lifecycle operations on GreenHelix."""

    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
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
"""Base client for all contract lifecycle operations on GreenHelix."""

    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
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
98% confidence
Finding
The method promises a complete audit trail for a specific contract, but it ignores contract_id and returns generic transaction analytics. In a contract enforcement system, this can mislead users into believing they have contract-specific evidence when they may be viewing unrelated or incomplete records, weakening auditability and dispute support.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The example walks readers through initiating contracts, creating escrow, monitoring obligations, enforcing breaches, and terminating vendors, but it does not place a local warning immediately around the executable-style workflow. For markdown files, omission of warnings around behaviors affecting user funds, counterparties, or system integrity is in scope even when the document is an educational guide.

Static analysis

No suspicious patterns detected.