The scope link ran one way: a program's scope showed whether each entry was
already a target. The question a hunter asks is the other one - I have this
asset, who pays for it - and nothing answered it.
`ProgramCoverageService` matches a host against every synced program's scope
through the machinery a watch already uses (`plan_scope`, `WatchItem.matches`,
`excluded_by`), so a wildcard entry covers its subtree, an exact entry covers
itself, and a program's own out-of-scope rows mark the match excluded rather
than hiding it. Measured against 7,173 synced scope rows on this instance:
`foo.bugcrowd.com` and `deep.nested.bugcrowd.com` resolve to Bugcrowd through
`*.bugcrowd.com/auth/*`, `notacme.com` is not a subtree of `*.acme.com`, and
`allegro.cz` comes back uncovered because that program lists it out of scope.
The target page carries it in the rail as Bounty: the program, its platform
and the scope entry that covers the target, hidden outside bug bounty mode.
`for_host` takes a bare hostname so a discovered asset can be asked the same
question next.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYop31s6BqDUt4TBs5mbwa