Everything a contract can see — `block.timestamp`, `blockhash`, `prevrandao` — is known or influenceable by block producers, and any value computed in the same transaction can be simulated by an attacker before committing.
// unsafe uint256 bad = uint256(keccak256(abi.encode(block.timestamp, msg.sender)));
Safe options are a verifiable random function oracle (Chainlink VRF) or a commit-reveal scheme where participants commit to a hashed secret first and reveal in a later block.