Zorya is a concolic executor that finds bugs in compiled x86-64 binaries and gives you the input that triggers them. It targets Go programs in particular (gc and TinyGo), and also handles C and partially C++, without needing the source code.
Zorya starts from the real state of the running program, captured with GDB (CPU registers, memory, threads), and executes Ghidra's P-Code with concrete and symbolic values. At each branch that depends on the input, it explores the other side and asks the Z3 solver for an input that reaches it. It reports Go panics (such as out-of-bounds indexing), NULL dereferences and divisions by zero, and its plugins detect data races, TOCTOU races and sends on closed channels across threads and goroutines.
The engine is written in Rust. It runs from a command-line launcher, from fuzzer-driven campaigns, or through an MCP server for AI agents.
The owl sees what darkness keeps; Zorya comes, and nothing sleeps.
🚧 Zorya is under active development. Breaking changes may happen. 🚧
git clone --recursive https://github.com/Ledger-Donjon/zorya
cd zorya
docker build -t zorya:latest .
docker run -it --rm \
--security-opt seccomp=unconfined \
--cap-add=SYS_PTRACE \
-v $(pwd)/results:/opt/zorya/results \
zorya:latestgit clone --recursive https://github.com/Ledger-Donjon/zorya
cd zorya
make ghidra-config
make allRun:
zorya <absolute-path-to-binary>Interactive mode asks for:
- language and compiler
- execution mode (
start,main,function,advanced) - optional function/address details
- optional binary arguments
- optional negated-path exploration
- plugin selection
Note: Program arguments (e.g.
os.Argsfor Go,argvfor C/C++) are automatically made symbolic by default. The--symbolic-registersand--symbolic-memoryflags are only needed inadvancedmode when you want fine-grained control over additional symbolic inputs.
Detailed interactive and flag behavior: doc/Usage.md
zorya <path> --lang <go|c|c++> [--compiler <tinygo|gc>] \
--mode <start|main|function|advanced> <addr> \
--thread-scheduling <all-threads|main-only> \
[--arg <arg1> [<arg2> ...]] \
[--negate-path-exploration|--no-negate-path-exploration] \
[--plugin "<plugin1 plugin2>"|all|none] \
[--force-pty] \
[--symbolic-registers "REG1 REG2|all"] \
[--symbolic-memory "0xADDR:SIZE ..."] \
[--no-symbolic-registers] [--no-symbolic-memory]Full flag reference and examples: doc/Usage.md
Running from macOS/Rosetta? Use the documented Linux runner workflow:
doc/Usage.md#linux-runner-workflow-manual-for-macosrosetta-users
and optional helper script scripts/zorya-remote-run.sh.
Zorya ships a Model Context Protocol server (zorya-mcp) that lets an LLM agent in Cursor, Claude Code, or GitHub Copilot drive the full analysis pipeline autonomously.
cargo build --releaseFull tool reference, workflow diagram, configuration for all supported clients, and usage examples: src/mcp/README.md
For automated campaigns on multiple addresses/configurations:
cargo build --release --bin zorya-fuzzer
./target/release/zorya-fuzzer --create-example fuzzer_config.json
./target/release/zorya-fuzzer fuzzer_config.jsonFull documentation: doc/Fuzzer.md
Zorya works best with debug symbols.
For Go:
tinygo build -gc=conservative -opt=0 .go build -gcflags=all="-N -l" .
More details: doc/Go-Binary-Analysis.md
You can validate your setup with the included test programs in tests/programs.
Minimal quick start:
zorya /absolute/path/to/zorya/tests/programs/crashme-go/crashmecrashme dereferences a nil pointer when the first byte of its argument is 'K'
(crash(arg byte) in tests/programs/crashme-go/main.go). Zorya symbolizes the
argument, solves the path constraint, and reports a satisfiable panic-triggering
state in results/FOUND_SAT_STATE.txt:
[*] SATISFIABLE STATE FOUND
Instruction Address: ... ← cmp $0x4b,%al ; je (arg == 'K')
Panic Address: ... ← je target: the p = nil; *p = 0 block
RESULTS
The program can panic if its inputs are the following:
- The input 'arg1_byte_0' must be 75 (unsigned: 75; signed: 75; ASCII: 'K')
Expected outputs and result files are documented in: doc/Quickstart.md
Detectors are event-driven plugins. The core executor fires typed events onto an event bus; each plugin subscribes only to the events it needs, keeps private state, and reads engine state through a read-only context. Every handler returns a verdict (continue, stop this path, report a finding, or abort), so detectors coexist without touching the core.
The Volos data-race detector, the TOCTOU check-use race detector, and the ChanCheck send-on-closed-channel detector are implemented (shaded); the scheduler, the WaitGroup invariant checker, and a weak-memory-model plugin are planned subscribers on the same bus. See doc/Plugins.md for the plugin API.
Zorya detects Time-of-Check-Time-of-Use vulnerabilities through overlay concolic execution. When a vulnerability is gated behind a specific input, Zorya uses Z3 to solve the triggering condition and reports it in source-level terms:
zorya tests/programs/toctou-test2-with-input/toctou-test2-with-input \
--lang go --compiler gc --mode main \
--thread-scheduling all-threads --arg "a" \
--negate-path-exploration --plugin "toctou chancheck"
Output in results/plugin_findings.txt:
[toctou::overlay-check-reachable] Potential TOCTOU: SO_PEERCRED(fd=<runtime-assigned>)
reachable on input-gated path (use not reached in overlay)
Triggering input (Z3-solved): os.Args[1][0] = 0x02 (decimal 2)
This tells you that providing a first argument whose first byte is 2 reaches the getsockopt(SO_PEERCRED) → readlinkat(/proc/<pid>/exe) race window. The finding includes an attack narrative, reproduction steps, and mitigations.
Technical details were moved under doc/:
- Usage and CLI details: doc/Usage.md
- Quick start and expected outputs: doc/Quickstart.md
- Vulnerability detection: doc/Vulnerability-Detection.md
- Compiler-aware strategies: doc/Compiler-Aware-Strategies.md
- Overlay path analysis: doc/Overlay-Path-Analysis.md
- Analyzer routine: doc/AST-exploration-overlay-execution.png
- Strategy overview: doc/Strategies.md
- Multi-threading: doc/Multi-threading.md
- Go binary analysis details: doc/Go-Binary-Analysis.md
- Fuzzer reference: doc/Fuzzer.md
Demo on broken-calculator binary compiled with TinyGo: Demo
Pass the SALT 2026 presentation: Presentation
June 2026 - From TinyGo to gc Compiler: Extending Zorya's Concolic Framework to Real-World Go Binaries (ACM EASE 2026): ArXiv
@article{gorna2026tinygo,
title={From TinyGo to gc Compiler: Extending Zorya's Concolic Framework to Real-World Go Binaries},
author={Gorna, Karolina and Iooss, Nicolas and Seurin, Yannick and Khatoun, Rida and Makan, Keith},
journal={arXiv preprint arXiv:2605.03492},
year={2026},
note={Accepted at the 30th ACM International Conference on Evaluation and Assessment in Software Engineering (EASE 2026)}
}March 2026 - Zorya: Automated Concolic Execution of Single-Threaded Go Binaries (ACM SAC 2026): ACM Digital Library
@inproceedings{gorna2026zorya,
title={Zorya: Automated Concolic Execution of Single-Threaded Go Binaries},
author={Gorna, Karolina and Iooss, Nicolas and Seurin, Yannick and Khatoun, Rida},
booktitle={Proceedings of the 41st ACM/SIGAPP Symposium on Applied Computing},
pages={2037--2044},
year={2026}
}May 2025 - Exposing Go's Hidden Bugs: A Novel Concolic Framework (IEEE SERA 2025): IEEE Xplore
@INPROCEEDINGS{11449147,
author={Gorna, Karolina and Iooss, Nicolas and Seurin, Yannick and Khatoun, Rida},
booktitle={2025 IEEE/ACIS 23rd International Conference on Software Engineering Research, Management and Applications (SERA)},
title={Exposing Go’s Hidden Bugs: A Novel Concolic Framework},
year={2025},
pages={1-6},
keywords={Couplings;Concurrent computing;Computer languages;Runtime;Static analysis;Fuzzing;Explosions;Security;Protection;Testing;Concolic execution;Go;Invariant testing;Vulnerabilities detection;P-Code},
doi={10.1109/SERA65747.2025.11449147}
}Evaluation repository: Zorya Evaluation
Evaluation Go dataset: Logic-Bombs-Go
Bugs discovered with Zorya on real-world open-source projects. Last update: August, 21st 2026.
| Repository | Bug / Vuln type | Report | Status |
|---|---|---|---|
| OOB / Slice bounds | |||
| mandiant/gopacket | OOB slice | #23 | Fixed |
| mandiant/gopacket | OOB slice | #25 | Fixed |
| 0xPolygon/bor | OOB slice | #2221 | Fixed |
| seaweedfs/seaweedfs | OOB slice | PR #9712 | Fixed |
| seaweedfs/seaweedfs | Index OOB | PR #9713 | Fixed |
| zeromicro/go-zero | OOB slice | #5614 | Fixed |
| multiformats/go-multiaddr | OOB slice | PR #289 | Fixed |
| pion/dtls | Index OOB | GHSA-wg4g-wm44-ch5j / CVE-2026-54908 | Fixed (medium) |
| pion/stun | OOB slice | GHSA-34rh-wp3j-6cxc / CVE-2026-54909 | Fixed (medium) |
| zeromicro/go-zero | OOB slice | #5607 | Fixed |
| multiformats/go-multiaddr | OOB slice | #288 | Fix ongoing |
| Integer overflow | |||
| gochain/gochain | Integer overflow | GHSA-rmvq-87f6-4pfc | Fixed |
| erpc/erpc | Integer overflow | #869 | Reported |
| trufnetwork/kwil-db | Integer overflow | #1701 | Reported |
| cometbft/cometbft | Integer overflow | #5846 | Fixed |
| gnolang/gno | Integer overflow | #5639 | Fix ongoing |
| XinFinOrg/XDPoSChain | Integer underflow | #2362 | Fixed |
| kedacore/keda | Float-to-int overflow | #7796 | Closed (not planned) |
| multiversx/mx-chain-go | Float-to-int64 overflow | Private disclosure | Reported |
| LeJamon/go-xrpl | Int64 wrap (MPT amount) | GHSA-xv89-94jf-8vx2 / CVE-2026-61693 | Fix ongoing |
| LeJamon/go-xrpl | Uint64 mul overflow (MPT amount) | GHSA-j5cw-qr86-mmv7 / CVE-2026-61694 | Fixed |
| Nil pointer dereference | |||
| runatlantis/atlantis | Nil pointer dereference | #6492 | Fixed |
| crossplane-contrib/provider-http | Nil pointer dereference | #178 | Fix ongoing |
| kedacore/keda | Nil pointer dereference | #7798 | Fixed |


