From 01775e240c9ba1b7bcc6b2e783d2f9292812b9d6 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Fri, 6 Mar 2026 16:56:59 +0000
Subject: [PATCH 1/5] feat
---
spec/Middlewares.spec.js | 50 ++++++++++++++++++++++++++++++++++++++
src/Config.js | 2 ++
src/Options/Definitions.js | 6 +++++
src/Options/docs.js | 1 +
src/Options/index.js | 3 +++
src/ParseServer.ts | 1 +
src/middlewares.js | 10 ++++++++
7 files changed, 73 insertions(+)
diff --git a/spec/Middlewares.spec.js b/spec/Middlewares.spec.js
index 57dca22b0e..8e1e04f8e5 100644
--- a/spec/Middlewares.spec.js
+++ b/spec/Middlewares.spec.js
@@ -7,6 +7,7 @@ const AppCachePut = (appId, config) =>
...config,
maintenanceKeyIpsStore: new Map(),
masterKeyIpsStore: new Map(),
+ readOnlyMasterKeyIpsStore: new Map(),
});
describe('middlewares', () => {
@@ -207,6 +208,55 @@ describe('middlewares', () => {
expect(fakeReq.auth.isMaster).toBe(true);
});
+ it('should not succeed and log if the ip does not belong to readOnlyMasterKeyIps list', async () => {
+ const logger = require('../lib/logger').logger;
+ spyOn(logger, 'error').and.callFake(() => {});
+ AppCachePut(fakeReq.body._ApplicationId, {
+ masterKeyIps: ['0.0.0.0/0'],
+ readOnlyMasterKey: 'readOnlyMasterKey',
+ readOnlyMasterKeyIps: ['10.0.0.1'],
+ });
+ fakeReq.ip = '127.0.0.1';
+ fakeReq.headers['x-parse-application-id'] = fakeReq.body._ApplicationId;
+ fakeReq.headers['x-parse-master-key'] = 'readOnlyMasterKey';
+
+ const error = await middlewares.handleParseHeaders(fakeReq, fakeRes, () => {}).catch(e => e);
+
+ expect(error).toBeDefined();
+ expect(error.message).toEqual('unauthorized');
+ expect(logger.error).toHaveBeenCalledWith(
+ `Request using read-only master key rejected as the request IP address '127.0.0.1' is not set in Parse Server option 'readOnlyMasterKeyIps'.`
+ );
+ });
+
+ it('should succeed if the ip does belong to readOnlyMasterKeyIps list', async () => {
+ AppCachePut(fakeReq.body._ApplicationId, {
+ masterKeyIps: ['0.0.0.0/0'],
+ readOnlyMasterKey: 'readOnlyMasterKey',
+ readOnlyMasterKeyIps: ['10.0.0.1'],
+ });
+ fakeReq.ip = '10.0.0.1';
+ fakeReq.headers['x-parse-application-id'] = fakeReq.body._ApplicationId;
+ fakeReq.headers['x-parse-master-key'] = 'readOnlyMasterKey';
+ await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
+ expect(fakeReq.auth.isMaster).toBe(true);
+ expect(fakeReq.auth.isReadOnly).toBe(true);
+ });
+
+ it('should allow any ip to use readOnlyMasterKey if readOnlyMasterKeyIps is 0.0.0.0/0', async () => {
+ AppCachePut(fakeReq.body._ApplicationId, {
+ masterKeyIps: ['0.0.0.0/0'],
+ readOnlyMasterKey: 'readOnlyMasterKey',
+ readOnlyMasterKeyIps: ['0.0.0.0/0'],
+ });
+ fakeReq.ip = '10.0.0.1';
+ fakeReq.headers['x-parse-application-id'] = fakeReq.body._ApplicationId;
+ fakeReq.headers['x-parse-master-key'] = 'readOnlyMasterKey';
+ await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
+ expect(fakeReq.auth.isMaster).toBe(true);
+ expect(fakeReq.auth.isReadOnly).toBe(true);
+ });
+
it('can set trust proxy', async () => {
const server = await reconfigureServer({ trustProxy: 1 });
expect(server.app.parent.settings['trust proxy']).toBe(1);
diff --git a/src/Config.js b/src/Config.js
index d5ea54691c..a3a56ea0f7 100644
--- a/src/Config.js
+++ b/src/Config.js
@@ -118,6 +118,7 @@ export class Config {
maintenanceKey,
maintenanceKeyIps,
readOnlyMasterKey,
+ readOnlyMasterKeyIps,
allowHeaders,
idempotencyOptions,
fileUpload,
@@ -158,6 +159,7 @@ export class Config {
this.validateSessionConfiguration(sessionLength, expireInactiveSessions);
this.validateIps('masterKeyIps', masterKeyIps);
this.validateIps('maintenanceKeyIps', maintenanceKeyIps);
+ this.validateIps('readOnlyMasterKeyIps', readOnlyMasterKeyIps);
this.validateDefaultLimit(defaultLimit);
this.validateMaxLimit(maxLimit);
this.validateAllowHeaders(allowHeaders);
diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js
index 7b28fc5c26..5529fc05ee 100644
--- a/src/Options/Definitions.js
+++ b/src/Options/Definitions.js
@@ -486,6 +486,12 @@ module.exports.ParseServerOptions = {
env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY',
help: 'Read-only key, which has the same capabilities as MasterKey without writes',
},
+ readOnlyMasterKeyIps: {
+ env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY_IPS',
+ help: "(Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.",
+ action: parsers.arrayParser,
+ default: ['127.0.0.1', '::1'],
+ },
requestContextMiddleware: {
env: 'PARSE_SERVER_REQUEST_CONTEXT_MIDDLEWARE',
help: 'Options to customize the request context using inversion of control/dependency injection.',
diff --git a/src/Options/docs.js b/src/Options/docs.js
index 8d0ad9445c..f83ca3a1e9 100644
--- a/src/Options/docs.js
+++ b/src/Options/docs.js
@@ -91,6 +91,7 @@
* @property {Any} push Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications
* @property {RateLimitOptions[]} rateLimit Options to limit repeated requests to Parse Server APIs. This can be used to protect sensitive endpoints such as `/requestPasswordReset` from brute-force attacks or Parse Server as a whole from denial-of-service (DoS) attacks.
ℹ️ Mind the following limitations:
- rate limits applied per IP address; this limits protection against distributed denial-of-service (DDoS) attacks where many requests are coming from various IP addresses
- if multiple Parse Server instances are behind a load balancer or ran in a cluster, each instance will calculate it's own request rates, independent from other instances; this limits the applicability of this feature when using a load balancer and another rate limiting solution that takes requests across all instances into account may be more suitable
- this feature provides basic protection against denial-of-service attacks, but a more sophisticated solution works earlier in the request flow and prevents a malicious requests to even reach a server instance; it's therefore recommended to implement a solution according to architecture and user case.
* @property {String} readOnlyMasterKey Read-only key, which has the same capabilities as MasterKey without writes
+ * @property {String[]} readOnlyMasterKeyIps (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.
* @property {Function} requestContextMiddleware Options to customize the request context using inversion of control/dependency injection.
* @property {RequestKeywordDenylist[]} requestKeywordDenylist An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns.
* @property {String} restAPIKey Key for REST calls
diff --git a/src/Options/index.js b/src/Options/index.js
index 83277a76d6..8bd5419399 100644
--- a/src/Options/index.js
+++ b/src/Options/index.js
@@ -82,6 +82,9 @@ export interface ParseServerOptions {
/* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key.
:DEFAULT: ["127.0.0.1","::1"] */
maintenanceKeyIps: ?(string[]);
+ /* (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.
+ :DEFAULT: ["127.0.0.1","::1"] */
+ readOnlyMasterKeyIps: ?(string[]);
/* Sets the app name */
appName: ?string;
/* Add headers to Access-Control-Allow-Headers */
diff --git a/src/ParseServer.ts b/src/ParseServer.ts
index 2e37c4728c..e1672aff5c 100644
--- a/src/ParseServer.ts
+++ b/src/ParseServer.ts
@@ -137,6 +137,7 @@ class ParseServer {
this.config = Config.put(Object.assign({}, options, allControllers));
this.config.masterKeyIpsStore = new Map();
this.config.maintenanceKeyIpsStore = new Map();
+ this.config.readOnlyMasterKeyIpsStore = new Map();
logging.setLogger(allControllers.loggerController);
}
diff --git a/src/middlewares.js b/src/middlewares.js
index 95b40aa7dd..7590a42920 100644
--- a/src/middlewares.js
+++ b/src/middlewares.js
@@ -270,6 +270,16 @@ export async function handleParseHeaders(req, res, next) {
req.config.readOnlyMasterKey &&
isReadOnlyMaster
) {
+ if (!checkIp(clientIp, req.config.readOnlyMasterKeyIps || [], req.config.readOnlyMasterKeyIpsStore)) {
+ const log = req.config?.loggerController || defaultLogger;
+ log.error(
+ `Request using read-only master key rejected as the request IP address '${clientIp}' is not set in Parse Server option 'readOnlyMasterKeyIps'.`
+ );
+ const error = new Error();
+ error.status = 403;
+ error.message = 'unauthorized';
+ throw error;
+ }
req.auth = new auth.Auth({
config: req.config,
installationId: info.installationId,
From afbbc21a949e93f46e303960628221bf8627c06b Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Fri, 6 Mar 2026 17:33:10 +0000
Subject: [PATCH 2/5] fix
https://github.com/parse-community/parse-server/pull/10115#discussion_r2896876551
---
src/middlewares.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/middlewares.js b/src/middlewares.js
index 7590a42920..06ed72e7ae 100644
--- a/src/middlewares.js
+++ b/src/middlewares.js
@@ -28,7 +28,7 @@ const getBlockList = (ipRangeList, store) => {
if (store.get('blockList')) { return store.get('blockList'); }
const blockList = new BlockList();
ipRangeList.forEach(fullIp => {
- if (fullIp === '::/0' || fullIp === '::') {
+ if (fullIp === '::/0' || fullIp === '::' || fullIp === '::0') {
store.set('allowAllIpv6', true);
return;
}
From e880fcda5ceef521b4bd1a8240299013ad25ecc0 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Fri, 6 Mar 2026 17:45:55 +0000
Subject: [PATCH 3/5] deprecate
---
DEPRECATIONS.md | 1 +
src/Deprecator/Deprecations.js | 5 +++++
src/Options/Definitions.js | 4 ++--
src/Options/docs.js | 2 +-
src/Options/index.js | 4 ++--
5 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md
index 707901612f..d3e4825d20 100644
--- a/DEPRECATIONS.md
+++ b/DEPRECATIONS.md
@@ -18,6 +18,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h
| DEPPS12 | Database option `allowPublicExplain` defaults to `false` | [#7519](https://github.com/parse-community/parse-server/issues/7519) | 8.5.0 (2025) | 9.0.0 (2026) | changed | - |
| DEPPS13 | Config option `enableInsecureAuthAdapters` defaults to `false` | [#9667](https://github.com/parse-community/parse-server/pull/9667) | 8.0.0 (2025) | 9.0.0 (2026) | changed | - |
| DEPPS14 | Config option `pages.encodePageParamHeaders` defaults to `true` | [#10063](https://github.com/parse-community/parse-server/issues/10063) | 9.4.0 (2026) | 10.0.0 (2027) | deprecated | - |
+| DEPPS15 | Config option `readOnlyMasterKeyIps` defaults to `['127.0.0.1', '::1']` | [#10115](https://github.com/parse-community/parse-server/pull/10115) | 9.5.0 (2026) | 10.0.0 (2027) | deprecated | - |
[i_deprecation]: ## "The version and date of the deprecation."
[i_change]: ## "The version and date of the planned change."
diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js
index 9b57f1be44..9093018f48 100644
--- a/src/Deprecator/Deprecations.js
+++ b/src/Deprecator/Deprecations.js
@@ -26,4 +26,9 @@ module.exports = [
changeNewDefault: 'true',
solution: "Set 'pages.encodePageParamHeaders' to 'true' to URI-encode non-ASCII characters in page parameter headers.",
},
+ {
+ optionKey: 'readOnlyMasterKeyIps',
+ changeNewDefault: '["127.0.0.1", "::1"]',
+ solution: "Set 'readOnlyMasterKeyIps' to the IP addresses that should be allowed to use the read-only master key, or to '[\"127.0.0.1\", \"::1\"]' to restrict access to localhost.",
+ },
];
diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js
index 5529fc05ee..f265f57c99 100644
--- a/src/Options/Definitions.js
+++ b/src/Options/Definitions.js
@@ -488,9 +488,9 @@ module.exports.ParseServerOptions = {
},
readOnlyMasterKeyIps: {
env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY_IPS',
- help: "(Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.",
+ help: "(Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['0.0.0.0/0', '::0']` which means that any IP address is allowed to use the read-only master key. It is recommended to set this option to `['127.0.0.1', '::1']` to restrict access to `localhost`.",
action: parsers.arrayParser,
- default: ['127.0.0.1', '::1'],
+ default: ['0.0.0.0/0', '::0'],
},
requestContextMiddleware: {
env: 'PARSE_SERVER_REQUEST_CONTEXT_MIDDLEWARE',
diff --git a/src/Options/docs.js b/src/Options/docs.js
index f83ca3a1e9..8278838340 100644
--- a/src/Options/docs.js
+++ b/src/Options/docs.js
@@ -91,7 +91,7 @@
* @property {Any} push Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications
* @property {RateLimitOptions[]} rateLimit Options to limit repeated requests to Parse Server APIs. This can be used to protect sensitive endpoints such as `/requestPasswordReset` from brute-force attacks or Parse Server as a whole from denial-of-service (DoS) attacks.
ℹ️ Mind the following limitations:
- rate limits applied per IP address; this limits protection against distributed denial-of-service (DDoS) attacks where many requests are coming from various IP addresses
- if multiple Parse Server instances are behind a load balancer or ran in a cluster, each instance will calculate it's own request rates, independent from other instances; this limits the applicability of this feature when using a load balancer and another rate limiting solution that takes requests across all instances into account may be more suitable
- this feature provides basic protection against denial-of-service attacks, but a more sophisticated solution works earlier in the request flow and prevents a malicious requests to even reach a server instance; it's therefore recommended to implement a solution according to architecture and user case.
* @property {String} readOnlyMasterKey Read-only key, which has the same capabilities as MasterKey without writes
- * @property {String[]} readOnlyMasterKeyIps (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.
+ * @property {String[]} readOnlyMasterKeyIps (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['0.0.0.0/0', '::0']` which means that any IP address is allowed to use the read-only master key. It is recommended to set this option to `['127.0.0.1', '::1']` to restrict access to `localhost`.
* @property {Function} requestContextMiddleware Options to customize the request context using inversion of control/dependency injection.
* @property {RequestKeywordDenylist[]} requestKeywordDenylist An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns.
* @property {String} restAPIKey Key for REST calls
diff --git a/src/Options/index.js b/src/Options/index.js
index 8bd5419399..96c94f9df1 100644
--- a/src/Options/index.js
+++ b/src/Options/index.js
@@ -82,8 +82,8 @@ export interface ParseServerOptions {
/* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key.
:DEFAULT: ["127.0.0.1","::1"] */
maintenanceKeyIps: ?(string[]);
- /* (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the read-only master key.
- :DEFAULT: ["127.0.0.1","::1"] */
+ /* (Optional) Restricts the use of read-only master key permissions to a list of IP addresses or ranges.
This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.
Special scenarios:
- Setting an empty array `[]` means that the read-only master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the read-only master key and effectively disables the IP filter.
Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.
Defaults to `['0.0.0.0/0', '::0']` which means that any IP address is allowed to use the read-only master key. It is recommended to set this option to `['127.0.0.1', '::1']` to restrict access to `localhost`.
+ :DEFAULT: ["0.0.0.0/0","::0"] */
readOnlyMasterKeyIps: ?(string[]);
/* Sets the app name */
appName: ?string;
From 2fd508f09e3ea1ac6ef2f010c12c8b00d3f7380c Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Fri, 6 Mar 2026 17:50:00 +0000
Subject: [PATCH 4/5] scheck
---
spec/SecurityCheckGroups.spec.js | 6 ++++++
.../CheckGroups/CheckGroupServerConfig.js | 17 +++++++++++++++++
2 files changed, 23 insertions(+)
diff --git a/spec/SecurityCheckGroups.spec.js b/spec/SecurityCheckGroups.spec.js
index 4f4d5fa6d9..c9a87ac8ca 100644
--- a/spec/SecurityCheckGroups.spec.js
+++ b/spec/SecurityCheckGroups.spec.js
@@ -35,6 +35,8 @@ describe('Security Check Groups', () => {
config.enableInsecureAuthAdapters = false;
config.graphQLPublicIntrospection = false;
config.mountPlayground = false;
+ config.readOnlyMasterKey = 'someReadOnlyMasterKey';
+ config.readOnlyMasterKeyIps = ['127.0.0.1', '::1'];
await reconfigureServer(config);
const group = new CheckGroupServerConfig();
@@ -45,6 +47,7 @@ describe('Security Check Groups', () => {
expect(group.checks()[4].checkState()).toBe(CheckState.success);
expect(group.checks()[5].checkState()).toBe(CheckState.success);
expect(group.checks()[6].checkState()).toBe(CheckState.success);
+ expect(group.checks()[8].checkState()).toBe(CheckState.success);
});
it('checks fail correctly', async () => {
@@ -54,6 +57,8 @@ describe('Security Check Groups', () => {
config.enableInsecureAuthAdapters = true;
config.graphQLPublicIntrospection = true;
config.mountPlayground = true;
+ config.readOnlyMasterKey = 'someReadOnlyMasterKey';
+ config.readOnlyMasterKeyIps = ['0.0.0.0/0'];
await reconfigureServer(config);
const group = new CheckGroupServerConfig();
@@ -64,6 +69,7 @@ describe('Security Check Groups', () => {
expect(group.checks()[4].checkState()).toBe(CheckState.fail);
expect(group.checks()[5].checkState()).toBe(CheckState.fail);
expect(group.checks()[6].checkState()).toBe(CheckState.fail);
+ expect(group.checks()[8].checkState()).toBe(CheckState.fail);
});
it_only_db('mongo')('checks succeed correctly (MongoDB specific)', async () => {
diff --git a/src/Security/CheckGroups/CheckGroupServerConfig.js b/src/Security/CheckGroups/CheckGroupServerConfig.js
index 0d1bc8c92b..904b00312e 100644
--- a/src/Security/CheckGroups/CheckGroupServerConfig.js
+++ b/src/Security/CheckGroups/CheckGroupServerConfig.js
@@ -117,6 +117,23 @@ class CheckGroupServerConfig extends CheckGroup {
}
},
}),
+ new Check({
+ title: 'Read-only master key IP range restricted',
+ warning:
+ 'The read-only master key can be used from any IP address, which increases the attack surface if the key is compromised.',
+ solution:
+ "Change Parse Server configuration to 'readOnlyMasterKeyIps: [\"127.0.0.1\", \"::1\"]' to restrict access to localhost, or set it to a list of specific IP addresses.",
+ check: () => {
+ if (!config.readOnlyMasterKey) {
+ return;
+ }
+ const ips = config.readOnlyMasterKeyIps || [];
+ const wildcards = ['0.0.0.0/0', '::/0', '::', '::0'];
+ if (ips.some(ip => wildcards.includes(ip))) {
+ throw 1;
+ }
+ },
+ }),
];
}
}
From cd282d59017ab267bfd4dadd6c0fbbced75d4bcf Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Fri, 6 Mar 2026 17:57:06 +0000
Subject: [PATCH 5/5] fix
https://github.com/parse-community/parse-server/pull/10115#discussion_r2897092873
---
src/Security/CheckGroups/CheckGroupServerConfig.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Security/CheckGroups/CheckGroupServerConfig.js b/src/Security/CheckGroups/CheckGroupServerConfig.js
index 904b00312e..76e441d572 100644
--- a/src/Security/CheckGroups/CheckGroupServerConfig.js
+++ b/src/Security/CheckGroups/CheckGroupServerConfig.js
@@ -128,7 +128,7 @@ class CheckGroupServerConfig extends CheckGroup {
return;
}
const ips = config.readOnlyMasterKeyIps || [];
- const wildcards = ['0.0.0.0/0', '::/0', '::', '::0'];
+ const wildcards = ['0.0.0.0/0', '0.0.0.0', '::/0', '::', '::0'];
if (ips.some(ip => wildcards.includes(ip))) {
throw 1;
}