The public constructor WalletsIn(Path pth) at src/main/java/io/zold/api/WalletsIn.java:55-61 instantiates the inner randomizer with new Random(), and create() at line 96 derives every new wallet identifier from Long.toHexString(this.random.nextLong()). The default java.util.Random is a 48-bit linear congruential generator whose output sequence is recoverable from a handful of observed samples.
In a value-bearing system this is the wrong class of generator. A caller that hands fresh wallet IDs back to a network observer lets that observer enumerate the next few IDs in advance and race the existence check at WalletsIn.java:104, or pre-compute path collisions for wallets the same process is about to create.
The fix is one line: switch the default in WalletsIn(Path pth) to new java.security.SecureRandom(). The two-arg constructor that takes an explicit Random stays as it is, so tests that inject a deterministic generator for reproducibility keep working unchanged.
The public constructor
WalletsIn(Path pth)atsrc/main/java/io/zold/api/WalletsIn.java:55-61instantiates the inner randomizer withnew Random(), andcreate()at line 96 derives every new wallet identifier fromLong.toHexString(this.random.nextLong()). The defaultjava.util.Randomis a 48-bit linear congruential generator whose output sequence is recoverable from a handful of observed samples.In a value-bearing system this is the wrong class of generator. A caller that hands fresh wallet IDs back to a network observer lets that observer enumerate the next few IDs in advance and race the existence check at
WalletsIn.java:104, or pre-compute path collisions for wallets the same process is about to create.The fix is one line: switch the default in
WalletsIn(Path pth)tonew java.security.SecureRandom(). The two-arg constructor that takes an explicitRandomstays as it is, so tests that inject a deterministic generator for reproducibility keep working unchanged.