Skip to content

Scope report views to the requesting user's authorized products#14870

Open
Maffooch wants to merge 2 commits into
bugfixfrom
fix/product-endpoint-report-scoping
Open

Scope report views to the requesting user's authorized products#14870
Maffooch wants to merge 2 commits into
bugfixfrom
fix/product-endpoint-report-scoping

Conversation

@Maffooch
Copy link
Copy Markdown
Contributor

Summary

Three closely-related issues in dojo/reports/views.py where the rendered Endpoint/Finding querysets were not scoped at the queryset-construction layer:

  1. product_endpoint_report (real cross-product leak) — the legacy non-Location branch built its Endpoint queryset by filtering on finding__active=True etc. without restricting to product=<pid>, so endpoints (and their associated findings) from unrelated products appeared in the rendered report. Added product=product to the Endpoint filter, and extended prefetch_related_endpoints_for_report in dojo/reports/queries.py with an optional product parameter so the prefetched Finding queryset is also scoped (defense in depth, since Endpoint.findings is an M2M and could in principle link cross-product findings). The widget caller keeps the default — its endpoint set already comes from a filter that the caller is responsible for scoping.

  2. report_findings — was constructed from Finding.objects.filter() (unscoped). The rendered output was nonetheless scoped because ReportFindingFilter.qs calls get_authorized_findings_for_queryset, but relying on the filter wrapper for authorization is fragile. Moved the authorization to the queryset-construction layer via get_authorized_findings(Permissions.Finding_View) to match the pattern used by ReportBuilder.get_findings.

  3. report_endpoints — same pattern as Installation issue #2, swapped to get_authorized_locations(Permissions.Location_View) / get_authorized_endpoints(Permissions.Location_View) so the authorization is visible at the view layer.

Added unittests/test_product_endpoint_report_scoping.py with two products, each with an engagement / test / active finding / endpoint, and a Reader-on-Product-A-only user:

  • The legacy product_endpoint_report tests check that the report for Product A only contains Product A's unique marker — and confirmed they fail without the queryset fix.
  • The /reports/findings and /reports/endpoints tests act as behavior locks for the new explicit scoping.

Test plan

  • `python manage.py test unittests.test_product_endpoint_report_scoping`
  • `python manage.py test unittests.test_pdf_report_rendering`
  • `python manage.py check`
  • `ruff check . --fix`

`product_endpoint_report` (legacy, non-Location branch) built its
Endpoint queryset by filtering on `finding__active=True` etc. without
restricting to `product=<pid>`, so endpoints (and their findings) from
unrelated products appeared in the rendered report. Added
`product=product` to the Endpoint filter, and extended
`prefetch_related_endpoints_for_report` with an optional `product`
parameter so the prefetched Finding queryset is also scoped.

While auditing the rest of the module, `report_findings` and
`report_endpoints` constructed their initial querysets from
`Finding.objects.filter()` / `Endpoint.objects.filter(...)` with no
authorization. The rendered output was scoped by the filter wrappers'
`qs` property, but moving authorization to the queryset-construction
layer (via `get_authorized_findings` /
`get_authorized_endpoints` / `get_authorized_locations`) matches the
pattern used by `ReportBuilder.get_findings` and removes the implicit
reliance on the filter wrapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Maffooch Maffooch requested a review from mtesauro as a code owner May 13, 2026 20:38
The legacy `product_endpoint_report` branch (and its `Endpoint`-based
test fixtures) is unreachable when `V3_FEATURE_LOCATIONS=True`, and the
`Endpoint` model raises NotImplementedError in that mode. Mark the
regression suite with `@skip_unless_v2` so it only runs against the
code path it actually covers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants