Back to skill

Security audit

Orderly Sdk Trading Workflows

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent trading-workflow guide, but it includes high-impact real-money transaction examples with underdeveloped safety controls and one verified order-direction bug.

Review this skill carefully before installing or using it to generate production code. Treat every generated deposit, withdrawal, leverage, order, and close-position path as real-money functionality requiring human confirmation, parameter review, validation, pending-state protection, and tests that verify the exact submitted side, symbol, quantity, price, and reduce-only settings.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:221
Finding
Limit Order May Execute with the Opposite Trade Direction Due to Stale React State<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 221–255 **Vulnerability Type**: Transaction integrity flaw caused by asynchronous state handling **Risk Level**: High ### Vulnerable Code ```tsx const [side, setSide] = useState(OrderSide.BUY); const placeLimitOrder = async () => { const order = { symbol, side, order_type: OrderType.LIMIT, order_price: parseFloat(price), order_quantity: parseFloat(quantity), }; const result = await submitOrder(order); if (result.success) { toast.success('Limit order placed!'); } }; return ( <div> <Input label="Price" value={price} onChange={(e) => setPrice(e.target.value)} /> <Input label="Quantity" value={quantity} onChange={(e) => setQuantity(e.target.value)} /> <Button color="buy" onClick={() => { setSide(OrderSide.BUY); placeLimitOrder(); }} > Buy </Button> <Button color="sell" onClick={() => { setSide(OrderSide.SELL); placeLimitOrder(); }} > Sell </Button> </div> ); ``` ### Technical Analysis React state updates through `setSide()` are asynchronous and are not guaranteed to update the `side` value within the current event-handler invocation. Both button handlers update the state and then immediately invoke `placeLimitOrder()`. That function reads `side` from the existing render closure, which may still contain the previous trade direction. Because the initial state is `OrderSide.BUY`, clicking **Sell** on the initial render can submit a buy order. The inverse can also occur after a prior state transition: clicking **Buy** while the current rendered state is `SELL` may submit a sell order. The order is sent to the financial API through `submitOrder(order)`, so this is not merely a display inconsistency. The stale value directly controls the direction of a potentially real transaction. ### Attack Path 1. The connected and authenticated user open ...[truncated 1680 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not use an asynchronously updated state value as the immediate source of authority for a financial transaction. Pass the selected side directly to the submission function: ```tsx const placeLimitOrder = async (selectedSide: OrderSide) => { const parsedPrice = Number(price); const parsedQuantity = Number(quantity); if ( !Number.isFinite(parsedPrice) || parsedPrice <= 0 || !Number.isFinite(parsedQuantity) || parsedQuantity <= 0 ) { toast.error('Enter a valid positive price and quantity.'); return; } const order = { symbol, side: selectedSide, order_type: OrderType.LIMIT, order_price: parsedPrice, order_quantity: parsedQuantity, }; const result = await submitOrder(order); if (result.success) { toast.success('Limit order placed!'); } }; <Button color="buy" onClick={() => placeLimitOrder(OrderSide.BUY)}> Buy </Button> <Button color="sell" onClick={() => placeLimitOrder(OrderSide.SELL)}> Sell </Button> ``` Additional hardening measures: 1. Display a confirmation step containing the exact side, symbol, price, quantity, leverage, and estimated exposure before submission. 2. Disable both submission buttons while an order request is pending to prevent duplicate orders. 3. Validate that price and quantity are finite, positive, within market precision constraints, and within account risk limits. 4. Add automated tests asserting that clicking Buy always submits `OrderSide.BUY` and clicking Sell always submits `OrderSide.SELL`, regardless of prior state. 5. Record and display the order direction returned by the API rather than showing a generic success message. 6. Use the SDK's validated order-entry abstraction where possible and keep transaction-critical values local to the explicit user action. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This skill provides step-by-step workflows for deposits, market and limit orders, leverage changes, position closure, and withdrawals without an upfront warning that these are irreversible or real-money, high-risk actions. In an agent-assisted setting, that omission can cause users or downstream agents to treat the content as routine boilerplate and execute financially dangerous operations without adequate confirmation or risk awareness.

Static analysis

No suspicious patterns detected.