From 872c070822ad477834a47234a65d702fe79c1ae7 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Fri, 15 May 2026 20:25:50 +0200 Subject: [PATCH 1/4] feat(backend): add throtteling by default --- docs/docs/start/config.md | 3 ++- src/backend/InvenTree/InvenTree/settings.py | 17 +++++++++++++++++ src/backend/InvenTree/config_template.yaml | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/docs/start/config.md b/docs/docs/start/config.md index 25b7fd6639..8aa77d81ea 100644 --- a/docs/docs/start/config.md +++ b/docs/docs/start/config.md @@ -136,7 +136,8 @@ Depending on how your InvenTree installation is configured, you will need to pay | `INVENTREE_X_FORWARDED_PROTO_NAME` | `x_forwarded_proto_name` | `HTTP_X_FORWARDED_PROTO` | Name of the header to use for forwarded protocol information | {{ configsetting("INVENTREE_SESSION_COOKIE_SECURE") }} Enforce secure session cookies | {{ configsetting("INVENTREE_COOKIE_SAMESITE") }} Session cookie mode. Must be one of `Strict | Lax | None | False`. Refer to the [mozilla developer docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) and the [django documentation]({% include "django.html" %}/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE) for more information. | - +{{ configsetting("INVENTREE_THROTTLE_ANON") }} Throttle rate for anonymous users (e.g. '20/minute') | +{{ configsetting("INVENTREE_THROTTLE_USER") }} Throttle rate for authenticated users (e.g. '5/second') | ### Debug Mode diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index 3aa32669be..a55d3e4a79 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -525,6 +525,8 @@ REST_FRAMEWORK = { 'DEFAULT_METADATA_CLASS': 'InvenTree.metadata.InvenTreeMetadata', 'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer'], 'TOKEN_MODEL': 'users.models.ApiToken', + 'DEFAULT_THROTTLE_CLASSES': [], + 'DEFAULT_THROTTLE_RATES': {}, } if DEBUG: @@ -540,6 +542,21 @@ if USE_JWT: JWT_AUTH_REFRESH_COOKIE = 'inventree-token' INSTALLED_APPS.append('rest_framework_simplejwt') +# Throtteling setup +THROTTLE_ANON = get_setting('INVENTREE_THROTTLE_ANON', 'throttle.anon', '20/minute') +THROTTLE_USER = get_setting('INVENTREE_THROTTLE_USER', 'throttle.user', '20/second') + +if THROTTLE_ANON and str(THROTTLE_ANON).lower() != 'none': + REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon'] = THROTTLE_ANON + REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'].append( + 'rest_framework.throttling.AnonRateThrottle' + ) +if THROTTLE_USER and str(THROTTLE_USER).lower() != 'none': + REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['user'] = THROTTLE_USER + REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'].append( + 'rest_framework.throttling.UserRateThrottle' + ) + # WSGI default setting WSGI_APPLICATION = 'InvenTree.wsgi.application' diff --git a/src/backend/InvenTree/config_template.yaml b/src/backend/InvenTree/config_template.yaml index 4b790e7c17..182a08354a 100644 --- a/src/backend/InvenTree/config_template.yaml +++ b/src/backend/InvenTree/config_template.yaml @@ -162,6 +162,11 @@ cors: # regex: +# Throttling is applied to the API by default to make DoS attacks more difficult; these can be disabled by setting them to None. +# throttle: +# anon: '20/minute' +# user: '20/second' + # MEDIA_ROOT is the local filesystem location for storing uploaded files #media_root: '/home/inventree/data/media' From e55c4cd93da6d32e7efe983526b81d0e12ceecf0 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Fri, 15 May 2026 20:34:33 +0200 Subject: [PATCH 2/4] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e12568aa52..0ea493be26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes - [#11893](https://github.com/inventree/InvenTree/pull/11893) bumps Node environment to version 24 LTS - this is only relevant if you build the frontend assets yourself +- [#11951](https://github.com/inventree/InvenTree/pull/11951) adds API throtteling by default to make DoS attacks more difficult. This can be disabled by setting the `INVENTREE_THROTTLE_ANON` and `INVENTREE_THROTTLE_USER` settings to `None` (either via environment variable or config file). The default throttling rates are 20 requests per minute for anonymous users, and 20 requests per second for authenticated users. ### Added From b822ea6e026df1450c3cdcf95e73ed772a74511e Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sat, 16 May 2026 12:18:55 +0200 Subject: [PATCH 3/4] ignore throtetling in debug mode --- src/backend/InvenTree/InvenTree/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index a55d3e4a79..db49499ee7 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -546,12 +546,12 @@ if USE_JWT: THROTTLE_ANON = get_setting('INVENTREE_THROTTLE_ANON', 'throttle.anon', '20/minute') THROTTLE_USER = get_setting('INVENTREE_THROTTLE_USER', 'throttle.user', '20/second') -if THROTTLE_ANON and str(THROTTLE_ANON).lower() != 'none': +if not DEBUG and THROTTLE_ANON and str(THROTTLE_ANON).lower() != 'none': REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon'] = THROTTLE_ANON REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'].append( 'rest_framework.throttling.AnonRateThrottle' ) -if THROTTLE_USER and str(THROTTLE_USER).lower() != 'none': +if not DEBUG and THROTTLE_USER and str(THROTTLE_USER).lower() != 'none': REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['user'] = THROTTLE_USER REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'].append( 'rest_framework.throttling.UserRateThrottle' From a9f7d418fbd36d5e0a9547e6bd65f45239b2e69e Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sat, 16 May 2026 12:19:54 +0200 Subject: [PATCH 4/4] increase threshold --- src/backend/InvenTree/InvenTree/settings.py | 2 +- src/backend/InvenTree/config_template.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index db49499ee7..4d2ae1547f 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -544,7 +544,7 @@ if USE_JWT: # Throtteling setup THROTTLE_ANON = get_setting('INVENTREE_THROTTLE_ANON', 'throttle.anon', '20/minute') -THROTTLE_USER = get_setting('INVENTREE_THROTTLE_USER', 'throttle.user', '20/second') +THROTTLE_USER = get_setting('INVENTREE_THROTTLE_USER', 'throttle.user', '60/second') if not DEBUG and THROTTLE_ANON and str(THROTTLE_ANON).lower() != 'none': REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon'] = THROTTLE_ANON diff --git a/src/backend/InvenTree/config_template.yaml b/src/backend/InvenTree/config_template.yaml index 182a08354a..3cc449234f 100644 --- a/src/backend/InvenTree/config_template.yaml +++ b/src/backend/InvenTree/config_template.yaml @@ -165,7 +165,7 @@ cors: # Throttling is applied to the API by default to make DoS attacks more difficult; these can be disabled by setting them to None. # throttle: # anon: '20/minute' -# user: '20/second' +# user: '60/second' # MEDIA_ROOT is the local filesystem location for storing uploaded files #media_root: '/home/inventree/data/media'