It's only a security vulnerability if there is a bug already present in the code. This mechanism is not introducing the vulnerability. In fact, it's helping find out the bug during development. At release runtime, the spare bits should always match.
I mean that if an object is deleted and its space in the array is reused for a new object, there's a small but non-zero chance that the spare bits will be identical, in which case the code would gain access to the new object when it is not supposed to. Or am I misunderstanding how the handle concept works?
Yeah, I think you are misunderstanding something here.
Yes, there is a non-zero chance that spare bits will be identical. But that's only relevant, if you have a bug in your code wherein you are trying to use a destroyed handle. If you are never using a destroyed handle, then the spare bits being identical is completely okay.
Another way to think of this is that the spare bits are optional. The interface is good even if there were no spare bits. The spare bits only add an additional probabilistic security check.
The fact that it's probabilistic is what makes it unreliable as a real security check. That's how I understood the original poster's concern. It might also lend a false sense of security, like most other solutions that don't actually solve the full problem.