You can block the specific offending IPs without collateral damage.
CGNATs reuse IPs so any IP block rule fairly quickly becomes somebody else's IP that you shouldn't be blocking.
If, however, you use IPv6, you don't need CGNAT and, while addresses may change, a blocked address won't suddenly get recycled to an unsuspecting user. In addition, if the allocation is static, you can block the whole network range and the problematic devices can't change their allocation sufficiently to escape the IP block.