From fdc8b11010131a3eae4825f6ffc07d6a370f7696 Mon Sep 17 00:00:00 2001 From: Adam Thomas Date: Wed, 15 Dec 2021 16:47:20 -0800 Subject: [PATCH] fix(codegen): escape regex literals in path segments We use regex to extract labeled path values, and literal path segments can contain unescaped regex literals that can both blow up deserialization and present ReDoS risks. While it's unlikely we will see these paths in practice, we should still escape special regex characters. --- .../integration/HttpBindingProtocolGenerator.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java index db223a0e807..81201cb964a 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java @@ -74,6 +74,7 @@ import software.amazon.smithy.typescript.codegen.TypeScriptWriter; import software.amazon.smithy.utils.ListUtils; import software.amazon.smithy.utils.OptionalUtils; +import software.amazon.smithy.utils.SetUtils; import software.amazon.smithy.utils.SmithyUnstableApi; /** @@ -83,6 +84,8 @@ public abstract class HttpBindingProtocolGenerator implements ProtocolGenerator { private static final Logger LOGGER = Logger.getLogger(HttpBindingProtocolGenerator.class.getName()); + private static final Set REGEX_CHARS = SetUtils.of('.', '*', '+', '?', '^', '$', '{', '}', '(', + ')', '|', '[', ']', '\\'); private final Set serializingDocumentShapes = new TreeSet<>(); private final Set deserializingDocumentShapes = new TreeSet<>(); @@ -1921,7 +1924,14 @@ private void readPath( } pathRegexBuilder.append(")"); } else { - pathRegexBuilder.append(segment.getContent()); + segment.getContent() + .chars() + .forEach(c -> { + if (REGEX_CHARS.contains((char) c)) { + pathRegexBuilder.append('\\'); + } + pathRegexBuilder.append((char) c); + }); } } writer.write("const pathRegex = new RegExp($S);", pathRegexBuilder.toString());