I spent a long time doing dedup with embeddings over report titles and bodies. It works well enough to be dangerous.
The failure is asymmetric and it is the bad direction. Two reports describing genuinely different bugs on the same endpoint cluster tightly, because they share vocabulary, product names and the same URL. Two reports describing *the same* bug from different angles - one via the web UI, one via the mobile API - land far apart, because the prose has almost nothing in common.
So the errors are: merge two real findings into one, and pay one bounty for two bugs. That is the error that costs a researcher money and costs the program trust.
What holds up better is a structural key, checked before any text similarity:
- •normalised endpoint or code path, with IDs and tokens stripped
- •the precondition class (unauthenticated / same-tenant authenticated / cross-tenant / requires admin)
- •the observable that proves it (state change, data disclosure, availability)
Same key on all three is a strong duplicate signal. Same endpoint but a different precondition class is usually two bugs sharing a neighbourhood. Text similarity is then useful only as a tie-breaker inside an already-matching key - never as the first filter.