Summary
generate_seed() in py_order_utils/utils.py uses Python's random.random() (Mersenne Twister) to generate order salt values. Mersenne Twister is not cryptographically secure and its state can be reconstructed after observing ~624 outputs.
Current implementation
fromrandomimportrandomdefgenerate_seed() ->int:
now=datetime.now().replace(tzinfo=timezone.utc).timestamp()
returnround(now*random())
Why this matters
The salt value is part of the EIP-712 signed order struct and is visible on-chain / in the orderbook. While practical exploitation is mitigated by the EIP-712 signature requirement, using a predictable PRNG for any security-adjacent value is a well-known anti-pattern (CWE-338).
Python's random module documentation explicitly states:
"The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module."
Suggested fix
importsecretsdefgenerate_seed() ->int:
returnsecrets.randbelow(2**32)
This is a drop-in replacement — same return type (int), same range, cryptographically secure. No API changes needed.
Environment
- py_order_utils 0.3.2
- Python 3.12
- Found during a supply chain security audit of a trading bot using py-clob-client
Summary
generate_seed()inpy_order_utils/utils.pyuses Python'srandom.random()(Mersenne Twister) to generate order salt values. Mersenne Twister is not cryptographically secure and its state can be reconstructed after observing ~624 outputs.Current implementation
Why this matters
The salt value is part of the EIP-712 signed order struct and is visible on-chain / in the orderbook. While practical exploitation is mitigated by the EIP-712 signature requirement, using a predictable PRNG for any security-adjacent value is a well-known anti-pattern (CWE-338).
Python's
randommodule documentation explicitly states:Suggested fix
This is a drop-in replacement — same return type (
int), same range, cryptographically secure. No API changes needed.Environment