Security: fix Javadoc injection in li-avro-codegen and class instantiation bypass in fast-serde - #604
Merged
leiykpt merged 3 commits intoJul 14, 2026
Conversation
…9410 bypass in fast-serde li-avro-codegen (SpecificRecordClassGenerator): - Add sanitizeDocForJavadoc() that escapes both JavaPoet format specifiers ($->$$) and Javadoc block-comment terminators (*/->'* /') before embedding schema doc strings in generated Javadoc. The '*/'-escaping closes the same injection vector that CVE-2024-47561 exploited in Avro's Velocity-based SpecificCompiler. - Apply the new sanitizer to enum, fixed, record, and field doc strings uniformly. Previously enum and fixed docs had no escaping at all; record and field docs only escaped '$' but not '*/'. fast-serde (SchemaAssistant): - Add validatedSpecificClassRef() which, before emitting a codeModel.ref() from a schema full name, loads the class and asserts it implements the expected Avro interface (SpecificRecord for RECORD, Enum for ENUM, SpecificFixed for FIXED). This prevents an attacker-controlled schema from causing fast-serde to generate code that instantiates an arbitrary class on the classpath -- the path that bypassed the SERIALIZABLE_CLASSES allowlist added to Avro core for CVE-2023-39410. - If the class is not found on the classloader (schema-evolution / compile-time absence), the check is skipped to preserve existing behaviour. - Thread classLoader from FastSerdeBase into SchemaAssistant; add backward-compat no-classLoader constructor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SrilakshmiBharadwaj
marked this pull request as ready for review
July 14, 2026 17:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR is a prerequisite for LinkedIn's Avro 1.10.2 CVE fork patch work. Before rolling out the patched Avro fork (
org.apache.avro:avro:1.10.2-li-N) to ~600 internal multiproducts, these two gaps in avro-util must be closed — otherwise the core CVE fixes in Avro are incomplete: fast-serde and li-avro-codegen carry their own vulnerable logic that bypasses the protections added to Avro core.Closes two security gaps in avro-util that bypass CVE fixes shipped in Apache Avro core:
1.
li-avro-codegen— Javadoc injection (CVE-2024-47561 analog)File:
avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.javaAvro's
SpecificCompiler(Velocity-based) escapes schemadocstrings before embedding them in generated code to fix CVE-2024-47561.li-avro-codegenuses JavaPoet instead of Velocity but had the same gap: schemadocstrings were added to Javadoc blocks without sanitization.Attack vector: A malicious schema with
"doc": "something */ public class Evil { static { Runtime.exec(...); } } //"would close the Javadoc block comment early and inject arbitrary Java code into the generated source.Fix: Add
sanitizeDocForJavadoc()that applies two escaping steps:$→$$— prevents JavaPoet from treating the string as a format specifier*/→* /— prevents premature Javadoc block comment terminationApplied uniformly to enum, fixed, record, and field doc strings. Previously enum and fixed had zero escaping; record and field only escaped
$.2.
fast-serde— Class instantiation bypass (CVE-2023-39410 analog)Files:
fastserde/avro-fastserde/src/main/java/com/linkedin/avro/fastserde/SchemaAssistant.java,FastSerdeBase.javaAvro core fixed CVE-2023-39410 by adding a
SERIALIZABLE_CLASSESallowlist toSpecificData.newInstance(). fast-serde bypasses this entirely: it generates Janino/javac source code that directly instantiates classes derived from schemafullNamefields, never going through the allowlist check.Attack vector: An attacker-controlled schema with
"name": "com.malicious.RCEClass"causes fast-serde to generate code likenew com.malicious.RCEClass(). If that class is on the classpath, it gets instantiated at deserialization time — no allowlist check applied.Fix: Add
validatedSpecificClassRef()inSchemaAssistantthat loads the class referenced bygetSchemaFullName(schema)and asserts it implements the expected Avro interface (SpecificRecordfor RECORD,Enumfor ENUM,SpecificFixedfor FIXED) before emitting acodeModel.ref(). If the class is not found on the classloader (schema-evolution scenario), the check is skipped to preserve existing behaviour.Thread
classLoaderfromFastSerdeBaseintoSchemaAssistant; backward-compat no-arg constructor preserved.Testing
./gradlew :fastserde:avro-fastserde-tests111:test :avro-codegen:test— all tests passRelated
SERIALIZABLE_CLASSESinSpecificData)escapeForJavadocinSpecificCompiler)