Security: Add fix, and tests, for Lorem Ipsum DoS issue (#2557)

This commit is contained in:
GCHQDeveloper581 2026-06-13 08:53:15 +01:00 committed by GitHub
parent dbcfb06d3e
commit 894560f6ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 114 additions and 3 deletions

View File

@ -8,6 +8,10 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { GenerateParagraphs, GenerateSentences, GenerateWords, GenerateBytes } from "../lib/LoremIpsum.mjs";
// arbitrary limits set to avoid DoS by requesting ridiculous amounts of data
const maxLoremWords = 100_000; // same limit also used for paragraphs/sentences
const maxLoremCharacters = 1_000_000;
/**
* Generate Lorem Ipsum operation
*/
@ -47,9 +51,7 @@ class GenerateLoremIpsum extends Operation {
*/
run(input, args) {
const [length, lengthType] = args;
if (length < 1) {
throw new OperationError("Length must be greater than 0");
}
checkLimits(lengthType, length);
switch (lengthType) {
case "Paragraphs":
return GenerateParagraphs(length);
@ -68,3 +70,32 @@ class GenerateLoremIpsum extends Operation {
}
export default GenerateLoremIpsum;
/**
* check combined validity of lengthType and length arguments
* @param {string} lengthType
* @param {number} length
* @throws {OperationError}
*/
function checkLimits(lengthType, length) {
if (length < 1) {
throw new OperationError("Length must be greater than 0");
}
switch (lengthType) {
case "Paragraphs":
case "Sentences":
case "Words":
if (length > maxLoremWords) {
throw new OperationError("Length must be less than " + maxLoremWords);
}
break;
case "Bytes":
if (length > maxLoremCharacters) {
throw new OperationError("Length must be less than " + maxLoremCharacters);
}
break;
default:
throw new OperationError("Invalid length type");
}
}

View File

@ -0,0 +1,80 @@
/**
* Generate Lorem Ipsum tests
*
* @author GCHQDeveloper581
* @copyright Crown Copyright 2025
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Generate Lorem Ipsum: Exceeds Word Limit",
input: "",
expectedOutput: "Length must be less than 100000",
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [999_999, "Words"]
},
],
},
{
name: "Generate Lorem Ipsum: Within Word Limit",
input: "",
// each word is >= 3 characters long, so expect at least 3000 characters
expectedMatch: /.{3000,}/s,
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [1000, "Words"]
},
],
},
{
name: "Generate Lorem Ipsum: Exceeds Byte Limit",
input: "",
expectedOutput: "Length must be less than 1000000",
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [1_000_001, "Bytes"]
},
],
},
{
name: "Generate Lorem Ipsum: Exceeds Sentence Limit",
input: "",
expectedOutput: "Length must be less than 100000",
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [999_999, "Sentences"]
},
],
},
{
name: "Generate Lorem Ipsum: Exceeds Paragraph Limit",
input: "",
expectedOutput: "Length must be less than 100000",
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [999_999, "Paragraphs"]
},
],
},
{
name: "Generate Lorem Ipsum: Incorrect lengthType",
input: "",
expectedOutput: "Invalid length type",
recipeConfig: [
{
"op": "Generate Lorem Ipsum",
"args": [999_999, "Novels"]
},
],
},
]);