That is correct, but the problem is that HashSet is also allowed to delete random files on disk (or modify other Vecs) when Hash::hash does not cannot, e.g. because it's not implemented in std. This makes a non-unsafe implementation of Hash causing other unsafe code (edit: that relies on any behavior of std) to be unsound. And that's something we don't want to happen, I believe.
I think what I would like is that an impl Hash for some_module::SomeType isn't able to mess up how Vec behaves, for example. And that's a reasonable demand, I think.
So the problem is while Hash::hash may cause panics or delete files on disk, it should never be able to mess with std::Vec as long as it's not containing any unsafe code. But given the unspecified behavior of std::collections::HashSet, for example, it may mess up Vec. Hence the problem with unsoundness.
So the problem is that HashSet can do more harm than Hash::hash can do. In combination with unsafe, it can even lead to UB (which shouldn't happen if Hash::hash does not use unsafe at all).
Of course this is a theoretical problem, as we know the current implementation of HashSet doesn't. But it makes soundness checks formally impossible. It's really a documentation issue.
(But maybe I'm missing something here.)
I would agree if Rust didn't came with the concept of ruling out UB when all unsafe code is sound. I.e. in other programming languages it wouldn't matter that much. But it kinda thwarts Rust's safety guarantees (or at least the ability to use them soundly, as defined by the reference).
P.S.: If we really want to allow HashSet to do "anything" due to a wrong Hash implementation, then Hash should be marked unsafe (which would cause a lot of problems). Currently, std fixes this by claiming that "anything but UB" can happen. But as shown in the discussion, there's no real practical difference between "anything" and "anything but UB" in this case.
P.P.S.: The problem would be less severe if HashSet wasn't part of std::collections but in a different crate, e.g. a third-party crate. That would still make it difficult to soundly write unsafe code that utilizes HashSet (or any other datatypes from that hypothetical crate), but it wouldn't affect unsafe code that utilizes std. And the latter is the problem here, I think.