Potential prefix exhaustion when reserving available IPs #4697

Closed
opened 2025-12-29 19:19:35 +01:00 by adam · 3 comments
Owner

Originally created by @jeromer on GitHub (Mar 25, 2021).

NetBox version

v2.8.7

Python version

3.8

Steps to Reproduce

  1. Create an API token
  2. Create a dummy prefix in ipam/prefixes. For example, create a 10.0.0.0/16 and keep its id somewhere
  3. Create a dummy payload in tmp/dummy.json with for example the following contents:
[
{"description": "Some description for IP 1"},
{"description": "Some description for IP 2"},
{"description": "Some description for IP 3"},
{"description": "Some description for IP 4"},
[...]
{"description": "Some description for IP 1000"}
]
  1. Now use the following curl command:
curl -s -X POST -H "Authorization: Token <your-api-token>" -H "accept: application/json" -H "Content-Type: application/json"  -d @/tmp/dummy.json http://<netbox>/api/ipam/prefixes/<prefix-id>/available-ips/
  1. Wait a couple of seconds and you will get a HTTP 201 response with all the IPs reserved in this prefix

Expected Behavior

Netbox should block large reservation payloads either by a hard-coded maximum value or by providing a configuration variable and refuses the HTTP requests.

Observed Behavior

It's possible to reserve an entire /16 in one go provided the HTTP POST payload size is accepted by the HTTP server. And once the payload is accepted then the full /16 will be reserved, it's slow but it works I just tried.

dummy.json.gz (A payload example which reserves an entire /16 in one go)

Originally created by @jeromer on GitHub (Mar 25, 2021). ### NetBox version v2.8.7 ### Python version 3.8 ### Steps to Reproduce 1. Create an API token 2. Create a dummy prefix in ipam/prefixes. For example, create a `10.0.0.0/16` and keep its id somewhere 3. Create a dummy payload in `tmp/dummy.json` with for example the following contents: ```json [ {"description": "Some description for IP 1"}, {"description": "Some description for IP 2"}, {"description": "Some description for IP 3"}, {"description": "Some description for IP 4"}, [...] {"description": "Some description for IP 1000"} ] ``` 4. Now use the following `curl` command: ``` curl -s -X POST -H "Authorization: Token <your-api-token>" -H "accept: application/json" -H "Content-Type: application/json" -d @/tmp/dummy.json http://<netbox>/api/ipam/prefixes/<prefix-id>/available-ips/ ``` 4. Wait a couple of seconds and you will get a HTTP `201` response with all the IPs reserved in this prefix ### Expected Behavior Netbox should block large reservation payloads either by a hard-coded maximum value or by providing a configuration variable and refuses the HTTP requests. ### Observed Behavior It's possible to reserve an entire `/16` in one go provided the HTTP POST payload size is accepted by the HTTP server. And once the payload is accepted then the full `/16` will be reserved, it's slow but it works I just tried. [dummy.json.gz](https://github.com/netbox-community/netbox/files/6203538/dummy.json.gz) (A payload example which reserves an entire `/16` in one go)
adam added the type: bug label 2025-12-29 19:19:35 +01:00
adam closed this issue 2025-12-29 19:19:36 +01:00
Author
Owner

@jeremystretch commented on GitHub (Mar 25, 2021):

It's possible to reserve an entire /16 in one go provided the HTTP POST payload size is accepted by the HTTP server.

This sounds like it's working as intended. Why do you believe this is a bug?

@jeremystretch commented on GitHub (Mar 25, 2021): > It's possible to reserve an entire /16 in one go provided the HTTP POST payload size is accepted by the HTTP server. This sounds like it's working as intended. Why do you believe this is a bug?
Author
Owner

@jeromer commented on GitHub (Mar 25, 2021):

With this behavior it's too simple to (possibly mistakenly) reserve an entire prefix leaving no room for other users who would also need it, and generating some frustration afterwards because of the required cleanup. By limiting the amount of reservable IPs per request it's possible to avoid this kind of issue. I agree that a user who really wants to reserve and entire prefix could do it by simply looping until it's exhausted but this denotes a more suspicious behavior. And also a user could (also mistankenly ?) exhaust the wrong prefix, but fixing this would require per prefix permissions I think. I'm not sure it's available in Netbox.

The simple answer would be "just create a prefix with the right size" and that would be right, but with legacy production systems, it's never that easy.

The other reason is that it's also a way to be nice with the database and to avoid long lasting locks on this view. The reason why we have pagination when listing data is to 1) be nice with the database 2) UX. That's the same logic, but applied to database writes, in the context of prefix management.

In case you are curious I wrote a quick patch here : d21a49dd4d (hopefully this is idiomatic Django)

:)

@jeromer commented on GitHub (Mar 25, 2021): With this behavior it's too simple to (possibly mistakenly) reserve an entire prefix leaving no room for other users who would also need it, and generating some frustration afterwards because of the required cleanup. By limiting the amount of reservable IPs per request it's possible to avoid this kind of issue. I agree that a user who really wants to reserve and entire prefix could do it by simply looping until it's exhausted but this denotes a more suspicious behavior. And also a user could (also mistankenly ?) exhaust the wrong prefix, but fixing this would require per prefix permissions I think. I'm not sure it's available in Netbox. The simple answer would be "just create a prefix with the right size" and that would be right, but with legacy production systems, it's never that easy. The other reason is that it's also a way to be nice with the database and to avoid long lasting locks on this view. The reason why we have pagination when listing data is to 1) be nice with the database 2) UX. That's the same logic, but applied to database writes, in the context of prefix management. In case you are curious I wrote a quick patch here : https://github.com/jeromer/netbox/commit/d21a49dd4dc31389afb2ef6f3d091e6a037ce4de (hopefully this is idiomatic Django) :)
Author
Owner

@jeremystretch commented on GitHub (Mar 25, 2021):

It sounds like you're trying to fix a client-side problem in the application. No matter what approach you take, the problem remains that a user can reserve an entire prefix, inadvertently or otherwise.

I agree that a user who really wants to reserve and entire prefix could do it by simply looping until it's exhausted but this denotes a more suspicious behavior.

And loop they will, as soon as the limit is encountered. Suspicious behavior or not, the prefix will be exhausted almost as fast as making the single request anyway.

but fixing this would require per prefix permissions I think. I'm not sure it's available in Netbox.

In NetBox v2.9 and later, it's very easy to restrict the prefixes a user or group of users can create by assigning constrained permissions.

@jeremystretch commented on GitHub (Mar 25, 2021): It sounds like you're trying to fix a client-side problem in the application. No matter what approach you take, the problem remains that a user can reserve an entire prefix, inadvertently or otherwise. > I agree that a user who really wants to reserve and entire prefix could do it by simply looping until it's exhausted but this denotes a more suspicious behavior. And loop they will, as soon as the limit is encountered. Suspicious behavior or not, the prefix will be exhausted almost as fast as making the single request anyway. > but fixing this would require per prefix permissions I think. I'm not sure it's available in Netbox. In NetBox v2.9 and later, it's very easy to restrict the prefixes a user or group of users can create by assigning [constrained permissions](https://netbox.readthedocs.io/en/stable/administration/permissions/).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#4697