What version of protobuf and what language are you using?
Version: Google.Protobuf 3.34.1 (latest stable). Also confirmed against main at commit 514aceb (2026-04-11) - csharp/src/Google.Protobuf/ParsingPrimitives.cs:685 is unchanged across these versions.
Language: C#
What supported operating system version are you using (e.g. Linux, Windows) ?
Reproduced on Linux. The affected code is pure managed, so this should also reproduce on Windows/macOS.
What supported runtime / compiler version are you using (e.g. python version, gcc version)
.NET 10.0 SDK
What did you do?
- Create a .NET console app targeting
net8.0 or later, add Google.Protobuf 3.34.1
- Paste the following code:
using Google.Protobuf;
using Google.Protobuf.Reflection;
var inputs = new[]
{
("Varint32", "2affffffff672acc"),
("Varint64", "42fcffffff57d801"),
("LittleEndian32", "3affffffff67b534"),
("LittleEndian64", "42ffffffff673934"),
};
foreach (var (name, hex) in inputs)
{
try
{
FileDescriptorProto.Parser.ParseFrom(Convert.FromHexString(hex));
Console.WriteLine($"{name}: OK");
}
catch (InvalidProtocolBufferException)
{
Console.WriteLine($"{name}: InvalidProtocolBufferException (expected)");
}
catch (IndexOutOfRangeException)
{
Console.WriteLine($"{name}: IndexOutOfRangeException (bug)");
}
}
- Run the app.
What did you expect to see
All four inputs are malformed / truncated Protocol Buffers messages. ParseFrom should throw InvalidProtocolBufferException (the documented exception type for parse failures), letting callers handle them with a single catch.
What did you see instead?
All four inputs throw System.IndexOutOfRangeException from ParsingPrimitives.ReadRawByte. Callers that wrap ParseFrom in catch (InvalidProtocolBufferException) - the idiomatic pattern - will not catch it.
Output:
Varint32: IndexOutOfRangeException (bug)
Varint64: IndexOutOfRangeException (bug)
LittleEndian32: IndexOutOfRangeException (bug)
LittleEndian64: IndexOutOfRangeException (bug)
Representative stack trace (Varint32 case):
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Google.Protobuf.ParsingPrimitives.ReadRawByte(ReadOnlySpan`1& buffer, ParserInternalState& state)
at Google.Protobuf.ParsingPrimitives.ParseRawVarint32SlowPath(ReadOnlySpan`1& buffer, ParserInternalState& state)
at Google.Protobuf.ParsingPrimitives.ParseRawVarint32(ReadOnlySpan`1& buffer, ParserInternalState& state)
at Google.Protobuf.FieldCodec.<>c.<ForString>b__16_0(ParseContext& ctx)
at Google.Protobuf.Collections.RepeatedField`1.AddEntriesFrom(ParseContext& ctx, FieldCodec`1 codec)
at Google.Protobuf.Reflection.EnumDescriptorProto...InternalMergeFrom(ParseContext& input)
...
at Google.Protobuf.MessageParser`1.ParseFrom(Byte[] data)
The three other inputs produce structurally identical stacks ending in ParseRawVarint64SlowPath, ParseRawLittleEndian32SlowPath, and ParseRawLittleEndian64SlowPath respectively. All four reach the same final frame: ParsingPrimitives.ReadRawByte at buffer[state.bufferPos++].
Anything else we should know about your project / environment
Each of the four inputs is a two-level message: FileDescriptorProto containing a length-delimited inner message whose declared length is a 5-byte varint close to int.MaxValue. The trailing bytes of each input drive the inner sub-parser down a different ParseRaw*SlowPath — but the four paths all end at the same out-of-bounds read in ReadRawByte, so they likely share a single root cause in how parser state is maintained after consuming the inner length varint.
Found via coverage-guided fuzzing with AFL++ and SharpFuzz.
What version of protobuf and what language are you using?
Version: Google.Protobuf 3.34.1 (latest stable). Also confirmed against
mainat commit514aceb(2026-04-11) -csharp/src/Google.Protobuf/ParsingPrimitives.cs:685is unchanged across these versions.Language: C#
What supported operating system version are you using (e.g. Linux, Windows) ?
Reproduced on Linux. The affected code is pure managed, so this should also reproduce on Windows/macOS.
What supported runtime / compiler version are you using (e.g. python version, gcc version)
.NET 10.0 SDK
What did you do?
net8.0or later, addGoogle.Protobuf3.34.1What did you expect to see
All four inputs are malformed / truncated Protocol Buffers messages.
ParseFromshould throwInvalidProtocolBufferException(the documented exception type for parse failures), letting callers handle them with a singlecatch.What did you see instead?
All four inputs throw
System.IndexOutOfRangeExceptionfromParsingPrimitives.ReadRawByte. Callers that wrapParseFromincatch (InvalidProtocolBufferException)- the idiomatic pattern - will not catch it.Output:
Representative stack trace (Varint32 case):
The three other inputs produce structurally identical stacks ending in
ParseRawVarint64SlowPath,ParseRawLittleEndian32SlowPath, andParseRawLittleEndian64SlowPathrespectively. All four reach the same final frame:ParsingPrimitives.ReadRawByteatbuffer[state.bufferPos++].Anything else we should know about your project / environment
Each of the four inputs is a two-level message:
FileDescriptorProtocontaining a length-delimited inner message whose declared length is a 5-byte varint close toint.MaxValue. The trailing bytes of each input drive the inner sub-parser down a differentParseRaw*SlowPath— but the four paths all end at the same out-of-bounds read inReadRawByte, so they likely share a single root cause in how parser state is maintained after consuming the inner length varint.Found via coverage-guided fuzzing with AFL++ and SharpFuzz.