Reflected XSS: IPAddressAssignView puts an unvalidated return_url into the Cancel link
NetBox Edition
NetBox Community
NetBox Version
v4.7.1
Python Version
3.12
Steps to Reproduce
- Log in as any user with the ipam.view_ipaddress permission.
- Visit /ipam/ip-addresses/assign/?interface=1&return_url=javascript:alert(document.cookie).
- Click the Cancel button.
Expected Behavior
Cancel navigates back to a safe in-app page. A return_url that isn't a relative path or an http(s) URL on this host is ignored and replaced with a sensible default, the same way every other view handles it.
Observed Behavior
Cancel runs the attacker's JavaScript in the victim's session. From there the usual escalation applies — read the CSRF token, then act as the victim against the API.
Suspected Cause
IPAddressAssignView (netbox/ipam/views.py:1237) extends generic.ObjectView, which doesn't include GetReturnURLMixin. Both handlers read the parameter straight from the query string and hand it to the template:
- netbox/ipam/views.py:1256 (get)
- netbox/ipam/views.py:1273 (post)
The template writes it into an href at netbox/templates/ipam/ipaddress_assign.html:28. Django's autoescaping stops you from breaking out of the attribute, but it doesn't touch the URL scheme, so javascript: goes through untouched.
This is the only view that skips the check. Everywhere else the value goes through GetReturnURLMixin.get_return_url() (netbox/utilities/views.py:162), which calls safe_for_redirect() (netbox/utilities/request.py:124) and rejects anything that isn't http(s) on an allowed host. The other two raw reads, at netbox/netbox/views/generic/object_views.py:337 and :629, both validate the assembled URL before redirecting. There's no site-wide CSP that would block the payload — the only Content-Security-Policy header in the tree is on the attachment view (netbox/netbox/views/misc.py:162).
Proposed Fix
Add GetReturnURLMixin to the view and call self.get_return_url(request) in both get() and post().
Source: netbox-community/netbox