T09 · Insecure Skill Coding Practices
- Location
SKILL.md:221- Finding
Limit Order May Execute with the Opposite Trade Direction Due to Stale React State
- Content
View full analysis
{ 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 (setPrice(e.target.value)} /> setQuantity(e.target.value)} /> { setSide(OrderSide.BUY); placeLimitOrder(); }} > Buy { setSide(OrderSide.SELL); placeLimitOrder(); }} > Sell); ``` ### 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
View remediation
{ 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!'); } }; placeLimitOrder(OrderSide.BUY)}> Buy placeLimitOrder(OrderSide.SELL)}> Sell ``` 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. ]]>
