T09 · Insecure Skill Coding Practices
- Location
scripts/group_repricer.py:64- Finding
Exit operation may create an opposing position while incorrectly recording the original position as closed
- Content
View full analysis
Vulnerability Details
File Location:
scripts/group_repricer.py:64-75
Vulnerability Type: Incorrect position-closing and exposure accounting logic
Risk Level: HighVulnerable Code:
python def exit_position(client, market, price, venue, reason, live, signal=None): with st.locked_state(live) as s: pos = s["positions"].get(market.id) if not pos or pos["status"] != "open": return "no open position" r = _trade(client, signal=signal, market_id=market.id, side="no", amount=pos["cost"], venue=venue, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reason) if not getattr(r, "success", False): return f"exit failed: {getattr(r, 'error', None) or '?'}" st.close_position(s, market.id, proceeds=getattr(r, "cost", 0.0) or 0.0) return NoneTechnical Analysis
The Skill records entries as YES or NO purchases. When attempting to exit a held position, it submits a new trade with
side="no"and an amount equal to the original position's dollar cost. It then unconditionally marks the locally tracked position as closed whenever the new trade reports success.No code in the project verifies that purchasing NO is an SDK-supported close or sell operation for the existing YES position. It also does not verify the number of shares held, the number of shares offset by the new trade, or the venue's remaining net exposure. Using the original cost as the amount does not guarantee an equivalent hedge because the market price may have changed since entry.
Consequently, a successful SDK response can represent acquisition of a separate NO position rather than liquidation of the existing YES position. Local state nevertheless removes the original cost from
open_exposure_usd, causing subsequent risk controls to operate on potentially inaccurate information.Attack Path
This issue can be triggered during normal ...[truncated 1539 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace the opposing-side purchase with the SDK's documented explicit sell, redeem, reduce, or close-position operation.
- Track position quantities or shares rather than relying only on the original dollar cost.
- After an exit response, query the venue and verify the remaining position before marking local state as closed.
- Record actual proceeds, fees, filled quantity, partial-fill status, and remaining quantity.
- Reduce
open_exposure_usdonly by the exposure demonstrably removed from the venue. - Treat partial fills as partially open positions rather than fully closed positions.
- Reconcile all local positions with authoritative venue positions at startup and before each budget decision.
- Add tests covering changed prices, partial fills, rejected closes, YES and NO entries, and discrepancies between local and venue state.
- Fail closed when the venue cannot confirm that an exit removed the expected exposure.
