Membrane API Gateway returns 400 Bad Request with the title JSON Protection Violation when the jsonProtection plugin rejects the request body. The body exceeds a configured limit, is not well-formed JSON, is not JSON at all, or is a multipart body that cannot be processed.
The response contains the status 400 Bad Request, the title JSON Protection Violation, a detail that names the violation, for example Exceeded maxDepth., the fields line and column with the position in the body, the problem type https://membrane-api.io/problems/user and a link to this page. The type user means that the request caused the problem, not an internal failure of the gateway.
This detailed response is only sent when reportError is on. By default, it is on in development mode and off in production mode. With reportError off, the client receives a plain 400 Bad Request without details.
The jsonProtection plugin protects backends from oversized and deeply nested JSON documents that are used in denial of service attacks. It reads the body as a stream and stops as soon as a limit is exceeded, so the offending body never reaches the backend. See JSON Protection for an introduction.
The detail says which limit was exceeded:
| Limit | Restricts |
|---|---|
maxTokens | The total number of tokens in the document |
maxSize | The size of the body in bytes |
maxDepth | The nesting depth of objects and arrays |
maxStringLength | The length of string values |
maxKeyLength | The length of field names |
maxObjectSize | The number of fields in an object |
maxArraySize | The number of elements in an array |
The body has a syntax error, contains the same key twice in one object, or contains __proto__ as a key while blockProto is on, which is the default. __proto__ keys are used in prototype pollution attacks against JavaScript backends.
The Content-Type of the request, or of a part of a multipart request, is not a JSON type. With otherContentTypes set to reject, the default, such bodies are rejected.
A part is larger than maxSize, a part is itself a multipart, a part uses an unsupported Content-Transfer-Encoding, or the multipart structure is malformed.
line and column fields to find the offending part of the body.Content-Type such as application/json.api:
port: 2000
flow:
- jsonProtection:
maxDepth: 100
maxArraySize: 5000
target:
url: https://api.predic8.de
api:
port: 2000
flow:
- jsonProtection:
maxDepth: 100
maxArraySize: 5000
target:
url: https://api.predic8.de
To let non-JSON bodies or parts pass unchecked, for example file uploads next to a JSON part, set otherContentTypes: skip on the plugin.
Unlike most errors, this response is not shortened in production mode. Whenever it is sent, it contains the detail, the position in the body and the link to this page, even with production: true. In production mode, reportError is off by default, so clients usually receive a plain 400 Bad Request instead. If you set reportError: true explicitly, the details are sent in production, too. They reveal your configured limits, so turn them off unless your clients need them:
api:
port: 2000
flow:
- jsonProtection:
reportError: false
target:
url: https://api.predic8.de
api:
port: 2000
flow:
- jsonProtection:
reportError: false
target:
url: https://api.predic8.de
Configuration reference:
Tutorials with runnable examples:
Still stuck? See the troubleshooting guide or ask on GitHub Issues. For commercial support, contact info@predic8.de.