NetBox Security Testing: API Token, Network Inventory, IPAM Credentials, and Infrastructure Map

NetBox is the most widely deployed open-source IPAM (IP Address Management) and network documentation platform, used by network teams to document IP allocations, device inventory, rack layouts, and network topology. It is a particularly valuable reconnaissance target: it contains the complete IP address space with all allocated subnets and device management IPs, the full hardware inventory including device makes/models and rack locations, and VLAN/circuit documentation for the entire network. Key assessment areas: NetBox REST API tokens provide unauthenticated enumeration of the complete network topology; configuration.py stores the Django SECRET_KEY enabling session token forgery; the database password in configuration is often reused; webhook configurations store Slack and PagerDuty API keys; and the custom script execution feature in NetBox can be abused for server-side code execution with database access. This guide covers systematic NetBox security assessment.

Table of Contents

  1. API Token Authentication and Enumeration
  2. IP Address Space and Device Inventory Access
  3. Configuration Credential Extraction
  4. NetBox Security Hardening

API Token Authentication and Enumeration

# NetBox — API token authentication and user enumeration
NETBOX_URL="https://netbox.example.com"
API_TOKEN="your-netbox-api-token"

# Test API access — NetBox allows read-only API without authentication in some configurations
curl -s "${NETBOX_URL}/api/status/" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'NetBox version: {d.get(\"netbox-version\")}')
print(f'Django version: {d.get(\"django-version\")}')
print(f'Python version: {d.get(\"python-version\")}')
" 2>/dev/null

# With API token — full access
curl -s "${NETBOX_URL}/api/users/users/?limit=100" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('results',[])
total = d.get('count',0)
print(f'Users: {total}')
for u in users:
    print(f'  [{u.get(\"id\")}] {u.get(\"username\")} email={u.get(\"email\")} is_staff={u.get(\"is_staff\")} is_superuser={u.get(\"is_superuser\")}')
" 2>/dev/null

# List all API tokens — identify service account tokens
curl -s "${NETBOX_URL}/api/users/tokens/?limit=100" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
tokens = d.get('results',[])
print(f'API tokens: {d.get(\"count\",0)}')
for t in tokens:
    user = t.get('user',{})
    print(f'  {t.get(\"key\")} user={user.get(\"username\")} expires={t.get(\"expires\")} write_enabled={t.get(\"write_enabled\")}')
" 2>/dev/null

IP Address Space and Device Inventory Access

# NetBox IP address space and device inventory enumeration
NETBOX_URL="https://netbox.example.com"
API_TOKEN="your-netbox-api-token"

# Enumerate all IP addresses — complete IP space with device assignments
curl -s "${NETBOX_URL}/api/ipam/ip-addresses/?limit=200&status=active" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
ips = d.get('results',[])
total = d.get('count',0)
print(f'Allocated IP addresses: {total}')
for ip in ips[:30]:
    assigned = ip.get('assigned_object',{}) or {}
    device = assigned.get('device',{}) or {}
    print(f'  {ip.get(\"address\")} dns={ip.get(\"dns_name\")} device={device.get(\"name\",\"\")} role={ip.get(\"role\",{}).get(\"value\",\"\")}')
" 2>/dev/null

# Enumerate all prefixes — subnet allocations and VLAN assignments
curl -s "${NETBOX_URL}/api/ipam/prefixes/?limit=100" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
prefixes = d.get('results',[])
print(f'Prefixes/subnets: {d.get(\"count\",0)}')
for p in prefixes:
    site = p.get('site',{}) or {}
    vlan = p.get('vlan',{}) or {}
    print(f'  {p.get(\"prefix\")} site={site.get(\"name\")} vlan={vlan.get(\"vid\")} role={p.get(\"role\",{}).get(\"name\",\"\")}')
" 2>/dev/null

# Enumerate all devices — complete hardware inventory with management IPs
curl -s "${NETBOX_URL}/api/dcim/devices/?limit=200" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
devices = d.get('results',[])
print(f'Devices: {d.get(\"count\",0)}')
for dev in devices[:30]:
    prim = dev.get('primary_ip',{}) or {}
    rack = dev.get('rack',{}) or {}
    print(f'  {dev.get(\"name\")} ip={prim.get(\"address\")} rack={rack.get(\"name\")} role={dev.get(\"device_role\",{}).get(\"name\")}')
" 2>/dev/null

Configuration Credential Extraction

# NetBox configuration.py — SECRET_KEY and database credentials
# Default path: /opt/netbox/netbox/netbox/configuration.py

grep -E "SECRET_KEY|DATABASE|PASSWORD|ALLOWED_HOSTS" \
  /opt/netbox/netbox/netbox/configuration.py 2>/dev/null
# Django SECRET_KEY — enables HMAC session cookie forgery
# DATABASE PASSWORD — PostgreSQL password for all NetBox data

# NetBox webhooks — check for stored integration credentials
curl -s "${NETBOX_URL}/api/extras/webhooks/?limit=100" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
webhooks = d.get('results',[])
print(f'Webhooks: {len(webhooks)}')
for w in webhooks:
    print(f'  {w.get(\"name\")} url={w.get(\"payload_url\")} secret={w.get(\"secret\")}')
" 2>/dev/null
# Webhook payload URLs may include Slack, PagerDuty, or custom integration endpoints

# NetBox custom scripts — code execution with Django ORM access
# Custom scripts run as the NetBox web process user
curl -s "${NETBOX_URL}/api/extras/scripts/" \
  -H "Authorization: Token ${API_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
scripts = d.get('results',[])
print(f'Custom scripts: {len(scripts)}')
for s in scripts:
    print(f'  {s.get(\"id\")} description={s.get(\"description\")}')
" 2>/dev/null

NetBox Security Hardening

NetBox Security Hardening Checklist:
Security TestMethodRisk
Unauthenticated API access to network topologyGET /api/ipam/ip-addresses/ without Authorization header — if LOGIN_REQUIRED=False, returns all allocated IP addresses, device management IPs, and subnet documentation; complete network map without authenticationCritical
Django SECRET_KEY extraction for session forgeryRead /opt/netbox/netbox/netbox/configuration.py — SECRET_KEY enables HMAC session cookie signing; forged session cookies bypass authentication for any user account including superadminsCritical
Device inventory and rack layout enumerationGET /api/dcim/devices/ and /api/dcim/racks/ — maps complete hardware inventory with device types, management IPs, physical rack locations, and datacenter topology; comprehensive reconnaissance assetHigh
Webhook credential extractionGET /api/extras/webhooks/ — returns payload URLs and optional secrets for all configured webhooks; Slack webhook URLs and PagerDuty routing keys are readable by API users with extras view permissionHigh
API token enumeration with write access discoveryGET /api/users/tokens/ — lists all active API tokens with write_enabled flag; identifies tokens with write access for potential data modification or fake IP/device injection to corrupt network documentationMedium (requires admin API access)

Automate NetBox Security Testing

Ironimo tests NetBox deployments for unauthenticated API access to IP allocations and device inventory, SECRET_KEY extraction from configuration.py, API token enumeration and write access assessment, webhook credential extraction, custom script execution privilege testing, database credential access via configuration, complete network topology and VLAN enumeration, and datacenter rack layout disclosure testing.

Start free scan