ZKar parses Java serialization streams in pure Go
ZKar is a Java serialization protocol analysis tool implement in Go.
At a glance
- What is it?
- ZKar is a Go implementation of a Java serialization protocol parser and viewer that needs no CGO and no JDK, converts streams into Go structs and can rebuild them byte for byte. It is a work in progress, and its payload generator is still on the TODO list.
- Who is it for?
- ZKar fits a security engineer who needs to read Java serialization payloads in a Go toolchain without dragging in a JDK, or a Go developer building tooling around serialized Java objects. It does not fit someone looking for a finished payload generator, since the ysoserial implementation is marked work in progress, and it does not fit a project needing a stable API, because the README states there is no complete API document and no contribution guide.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A deserialization reader that needs no JVM
ZKar is a Java serialization protocol analysis tool implemented in Go, and the architectural choice is stated up front: the parser and viewer are pure Go, with no CGO and no JDK required. That is the whole reason the project exists as a separate thing rather than a wrapper. A Java serialization stream is a self-describing binary format, and reading one means walking a stream of type descriptors, class data blocks and object graphs. Doing that in Go means a payload can be parsed inside a Go service, a scanner or a CI job without provisioning a JVM, and the resulting data becomes ordinary Go values that the surrounding code can manipulate. The library form of the project, under the serz package, exposes a struct representation of a parsed serialization and a way to turn it back into bytes.
From protocol bytes to Go structs
The library API is short. You open a file, hand the reader to serz.FromReader, and get a serialization struct back or an error. From there, ToString gives you a readable rendering of what was in the stream. The repository carries a serz package, plus commons, class and rmi directories, which maps to the scope of the project: the core serialization protocol, shared helper types, class metadata handling and remote method invocation work in progress. The dependency list in go.mod is small, with urfave/cli for the command line, samber/lo for functional helpers, stretchr/testify for tests and a fork of litter used to pretty-print Go values, which is the sort of dependency you see when a tool prints nested structures and you want readable output rather than a wall of field names.
Round-trip fidelity is the claim that carries weight
The test section is where this project makes its strongest argument, and it makes it quantitatively. The README states that ZKar passed all ysoserial generated gadget parsing and rebuilding tests, meaning a gadget produced by ysoserial can be parsed by ZKar and the parsed structure converted back into a byte string equal to the original. The table lists thirty five ysoserial gadgets, from AspectJWeaver and BeanShell1 through the CommonsCollections family, Hibernate, Spring, URLDNS, Vaadin and Wicket, each with a parse result, a rebuild result and a parse time. The times range from about 21 microseconds for URLDNS and 22 for Myfaces1 up to roughly 2.1 milliseconds for JSON1 and 1.7 for MozillaRhino1, which says the parser is fast enough for interactive use. Round-trip equality is the property that matters most here, because a tool that parses but cannot rebuild is a viewer, not a protocol implementation.
The JDK8u20 payload breaks the format, so it needs a flag
One entry in the table is different. JDK8u20, marked with an asterisk and sourced from pwntester rather than ysoserial, parses and rebuilds but needs the --jdk8u20 flag on the dump command. The reason given is precise: the payload is not a valid serialized data stream, so ZKar has to be told to patch the data. That is a fair engineering decision rather than a bug, since a stream that violates the specification can only be handled by a special path, and the alternative would be guessing at intent on every malformed input. It is also a useful signal about how the tool behaves on hostile data generally. If a payload can be non-conforming, then parsing cannot assume conformance, which matters for a tool whose likely users are people looking at malformed or crafted streams.
The command line has three commands and one of them is unfinished
The utility wraps the library with urfave/cli and exposes a small command surface. Running the main file prints the name and usage banner, listing generate, dump and help, with generate described as generating Java serz attack payloads and dump as parsing the streams and dumping the struct. Dumping a payload file looks like this:
$ go run main.go dump -f "$(pwd)/testcases/ysoserial/CommonsBeanutils3.ser"The generate command is where the work in progress label bites. The feature list marks the ysoserial implementation in Go as WIP, and the TODO list still has the serialization payloads generator unchecked, alongside the Java bytecodes parser and generator and the RMI and LDAP implementation. The README opens by saying there is no complete API document and no contribution guide, so treat the command names as a sketch of the intended surface rather than a contract.
UTF-8 overlong encoding is supported, and it is the point
One completed TODO item is support for read and write UTF-8 overlong encoding, and there is a test file that demonstrates reading an existing payload and modifying it into a UTF-8 overlong encoding payload. That detail says a lot about what ZKar is for. Overlong encodings are a classic trick for smuggling bytes past a filter that expects canonical UTF-8, so a tool that can both produce and consume them sits on the offensive and the defensive side of the same line. The repository also carries an example directory with a convert test, a poc example and a main program, alongside a testcases directory holding the ysoserial payloads used by the test table. The MIT licence and the goreleaser configuration point at a project that is packaged for release rather than kept as a personal script.
Against the existing Java tooling
The README lists what it considers the alternatives, and the comparison is instructive. SerializationDumper is described as a tool to dump and rebuild Java serialization streams and Java RMI packet contents in a more human readable form, which is the same goal implemented in a different language. ysoserial is the proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization, so it is a companion rather than a competitor. The Java Deserialization Cheat Sheet is a reference for the vulnerability class itself. ZKar's differentiation is the language and the shape of the API: it drops the JVM requirement and produces Go structs you can pass around, at the cost of a project that is still incomplete and moving, with the last push on 2026-04-19 and release v1.6.0 on the same date, after v1.5.1 in February 2025 and v1.5.0 in August 2024.
Editorial conclusion
ZKar fits a security engineer who needs to read Java serialization payloads in a Go toolchain without dragging in a JDK, or a Go developer building tooling around serialized Java objects. It does not fit someone looking for a finished payload generator, since the ysoserial implementation is marked work in progress, and it does not fit a project needing a stable API, because the README states there is no complete API document and no contribution guide. Verify first that the Java classes you care about map cleanly onto the Go structs in the serz package, check the gadget coverage table for your specific chains, and remember the JDK8u20 payload needs the --jdk8u20 flag because it is not a valid serialization stream.
Frequently asked questions
Does ZKar need a JDK or CGO to parse Java serialization payloads?
No. The parser and viewer are pure Go, with no CGO or JDK required, which is the main reason the project exists separately from a Java-based tool. The library can be consumed from Go code with a go get of the module.
How do I dump a Java serialization payload with ZKar?
Use the dump command with the file flag, for example go run main.go dump -f "$(pwd)/testcases/ysoserial/CommonsBeanutils3.ser". It parses the stream and prints the structure, and the --jdk8u20 flag is needed for that particular payload because it is not a valid serialized data stream.
Can ZKar rebuild a payload after parsing it?
Yes. The README states that ZKar passed the ysoserial gadget parsing and rebuilding tests, so a parsed structure can be converted back into a byte string equal to the original, and a table lists the parse and rebuild results for thirty five gadgets with their parse times.
Is ZKar able to generate Java deserialization payloads?
Not yet. The ysoserial implementation in Go is marked work in progress, and the TODO list still has the serialization payloads generator unchecked, alongside the Java bytecodes parser and generator and the RMI and LDAP implementation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/phith0n-zkar)Was this useful?