# Security considerations
JSON Schema, if properly used, can replace data sanitisation. It doesn't replace other API security considerations. It also introduces additional security aspects to consider.
# Security contact
To report a security vulnerability, please use the Tidelift security contact (opens new window). Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.
# Untrusted schemas
Ajv treats JSON schemas as trusted as your application code. This security model is based on the most common use case, when the schemas are static and bundled together with the application.
If your schemas are received from untrusted sources (or generated from untrusted data) there are several scenarios you need to prevent:
- compiling schemas can cause stack overflow (if they are too deep)
- compiling schemas can be slow (e.g. #557 (opens new window))
- validating certain data can be slow
It is difficult to predict all the scenarios, but at the very least it may help to limit the size of untrusted schemas (e.g. limit JSON string length) and also the maximum schema object depth (that can be high for relatively small JSON strings). You also may want to mitigate slow regular expressions in pattern
and patternProperties
keywords.
Regardless the measures you take, using untrusted schemas increases security risks.
# Circular references in JavaScript objects
Ajv does not support schemas and validated data that have circular references in objects. See issue #802 (opens new window).
An attempt to compile such schemas or validate such data would cause stack overflow (or will not complete in case of asynchronous validation). Depending on the parser you use, untrusted data can lead to circular references.
# Security risks of trusted schemas
Some keywords in JSON Schemas can lead to very slow validation for certain data. These keywords include (but may be not limited to):
pattern
andformat
for large strings - in some cases usingmaxLength
can help mitigate it, but certain regular expressions can lead to exponential validation time even with relatively short strings (see ReDoS attack).patternProperties
for large property names - usepropertyNames
to mitigate, but some regular expressions can have exponential evaluation time as well.uniqueItems
for large non-scalar arrays - usemaxItems
to mitigate
Do NOT use allErrors in production
The suggestions above to prevent slow validation would only work if you do NOT use allErrors: true
in production code (using it would continue validation after validation errors).
You can validate your JSON schemas against this meta-schema (opens new window) to check that these recommendations are followed:
ajv = new Ajv({strictTypes: false}) // this option is required for this schema
const isSchemaSecure = ajv.compile(require("ajv/lib/refs/json-schema-secure.json"))
const schema1 = {format: "email"}
isSchemaSecure(schema1) // false
const schema2 = {format: "email", maxLength: MAX_LENGTH}
isSchemaSecure(schema2) // true
Untrusted data
Following all these recommendation is not a guarantee that validation using of untrusted data is safe - it can still lead to some undesirable results.
# ReDoS attack
Certain regular expressions can lead to the exponential evaluation time even with relatively short strings.
Please assess the regular expressions you use in the schemas on their vulnerability to this attack - see safe-regex (opens new window), for example.
By default, Ajv uses the regex engine built into Node.js. This engine has exponential worst-case performance. This performance (and ReDoS attacks) can be mitigated by using a linear-time regex engine. Ajv supports the use of a third-party regex engine for this purpose.
To use a third-party regex engine in Ajv, set the ajv.opts.code.regExp property to that regex engine during instantiation. Here we use Google’s RE2 engine as an example.
const Ajv = require("ajv")
const RE2 = require("re2")
const ajv = new Ajv({code: {regExp: RE2}})
For details about the interface of the regexp
option, see options.md under the docs folder.
Although linear-time regex engines eliminate ReDoS vulnerabilities, changing a regex engine carries some risk, including:
- Minor changes in regex syntax.
- Minor changes in regex semantics. For example, RE2 always interprets regexes in Unicode, and disagrees with JavaScript in its definition of whitespace. To avoid regressions, develop and test your regexes in the same regex engine that you use in production.
- May not support some advanced features, such as look-aheads or back-references.
- May have (minor) common-case performance degradation.
- Increases size of distributable (e.g. RE2 includes a non-trivial C component).
ReDoS attack
Some formats that ajv-formats (opens new window) package implements use regular expressions (opens new window) that can be vulnerable to ReDoS attack.
If you use Ajv to validate data from untrusted sources it is strongly recommended to consider the following:
- making assessment of "format" implementations in ajv-formats (opens new window).
- passing
"fast"
option to ajv-formats plugin (see its docs) that simplifies some of the regular expressions (although it does not guarantee that they are safe). - replacing format implementations provided by ajv-formats with your own implementations of "format" keyword that either use different regular expressions or another approach to format validation. Please see addFormat (opens new window) method.
- disabling format validation by ignoring "format" keyword with option
format: false
Whatever mitigation you choose, please assume all formats provided by ajv-formats as potentially unsafe and make your own assessment of their suitability for your validation scenarios.
# Content Security Policy
When using Ajv in a browser page with enabled Content Security Policy (CSP), script-src
directive must include 'unsafe-eval'
.
Cross-site scripting attacks
unsafe-eval
is NOT recommended in a secure CSP[1] (opens new window), as it has the potential to open the document to cross-site scripting (XSS) attacks.
In order to use Ajv without relaxing CSP, you can compile the schemas using CLI (opens new window) or programmatically in your build code - see Standalone validation code. Compiled JavaScript file can export one or several validation functions that have the same code as the schemas compiled at runtime.