Introduction
We thank the QAN team for their cooperation during this security assessment of the QAN Virtual Machine (QVM) execution pipeline.
QAN aims to provide a quantum-resistant Layer-1 blockchain supporting versatile smart contract development. Central to this is the QVM, designed for secure and deterministic execution across multiple programming languages. The audited workflow involves processing contract source code through a precompiler (creating a verifiable PEM format), a language-specific compiler (producing an ELF binary), and then execution of the smart contract.
Execution occurs within QEMU (initially within gokvm). Inside the VM, the Hermit engine ensures deterministic execution by intercepting the contract binary's system calls, managing scheduling, and controlling environmental factors. This layered approach seeks to deliver a robust, flexible, and verifiably consistent runtime for QAN smart contracts.
Document | |
|---|---|
| Name | Blockchain Protocol Review and Security Analysis Report for QANplatform |
| Audited By | Bartosz Barwikowski |
| Approved By | Nino Lipartiia |
| Website | https://qanplatform.com→ |
| Changelog | 18/04/2025 - Preliminary report |
| Changelog | 17/06/2025 - Pre-final report after remediation |
| Changelog | 18/07/2025 - Final report |
| Changelog | 25/07/2025 - Final report (Risk Section Update) |
| Platform | QAN |
| Language | Golang, Rust |
| Tags | Virtual Machine, Layer 1 |
| Methodology | https://hackenio.cc/blockchain_methodology→ |
Document
- Name
- Blockchain Protocol Review and Security Analysis Report for QANplatform
- Audited By
- Bartosz Barwikowski
- Approved By
- Nino Lipartiia
- Website
- https://qanplatform.com→
- Changelog
- 18/04/2025 - Preliminary report
- Changelog
- 17/06/2025 - Pre-final report after remediation
- Changelog
- 18/07/2025 - Final report
- Changelog
- 25/07/2025 - Final report (Risk Section Update)
- Platform
- QAN
- Language
- Golang, Rust
- Tags
- Virtual Machine, Layer 1
- Methodology
- https://hackenio.cc/blockchain_methodology→
Review Scope | |
|---|---|
| Repository | Encrypted zip archive with VM files, hermit, precompiler, and compiler |
| Commit (sha256sum) | Initial: c7feafc7ccd521656428d9a8e825bcbb84cc6a8ee9f2a658cad593c3d9613dc8 |
| Final: 9f032cb65887a646aa68df04a96800cf7e009755e1e06ea5a5a25fea16827ee5 |
Review Scope
- Repository
- Encrypted zip archive with VM files, hermit, precompiler, and compiler
- Commit (sha256sum)
- Initial: c7feafc7ccd521656428d9a8e825bcbb84cc6a8ee9f2a658cad593c3d9613dc8
- Final: 9f032cb65887a646aa68df04a96800cf7e009755e1e06ea5a5a25fea16827ee5
Audit Summary
QVM module was audited at this scope as a standalone module instead of being operated in a blockchain environment. More than 2821 unique test cases were evaluated to discover potential sources of non-determinism which produced 22 findings. All of the reported issues were fixed by QANplatform team. The system users should acknowledge all the risks summed up in the risks section of the report.
{FindingsVulnSeverityStatusTable}
Documentation quality
Mix of basic internal documentation and inherited docs from third-party components.
Some high-level information published on the official QANplatform website.
Understanding detailed interactions often requires reading code and scripts directly.
Documentation lags behind recent features and technical decisions.
Code quality
Multi-language codebase: primarily Go (build tools) and Rust (Hermit), with C/C++ (SDKs).
Extensive use of shell scripts and Dockerfiles for build orchestration.
Significant code duplication observed, especially across Dockerfiles for compilers/precompilers.
Demonstrates a modular structure separating key components (VMM, Compiler, Hermit).
Test coverage is limited, focusing on basic functionality.
Architecture quality
Project employs a modular design, separating VMM (QEMU, initially gokvm), compiler orchestration (qvm-compiler), deterministic execution (Hermit), and language-specific build components.
Utilizes QEMU virtualization.
Relies on the Hermit engine within the guest VM to enforce deterministic execution via syscall interception and controlled scheduling.
Features multi-language contract support as a core architectural goal, achieved through containerized compiler environments.
Host-guest communication for state interaction is dependent on a gRPC protocol over VirtIO networking.
Scalability model uses a VM pool; actual throughput constrained by host resources, VM lifecycle overhead, gRPC latency, and Hermit's performance impact.
The build pipeline (Precompiler/Compiler) currently runs outside the deterministic Hermit environment, creating a potential source of non-determinism in the overall process.
The multi-layered approach (virtualization, custom OS, deterministic overlay, build tools) contributes to significant overall system complexity.
System Overview
The QAN Virtual Machine (QVM) is a sophisticated execution environment engineered to operate smart contracts on the QAN blockchain platform. Its primary objective is to provide a secure, isolated, and multi-language compatible runtime that guarantees deterministic execution. Determinism is paramount in blockchain systems, ensuring that every validating node reaches the exact same state transition when processing the same transaction, regardless of the underlying hardware or timing variations. QVM achieves this through a multi-layered architecture involving specialized build tooling, KVM-based virtualization, and a dedicated deterministic execution engine.
The lifecycle of a smart contract within the QVM ecosystem begins with a flexible build pipeline designed to accommodate a wide array of programming languages. First stage involves the Precompiler. This tool processes the original source code, applying language-specific minification and compression techniques (like Brotli). The output is a standardized PEM-encoded file containing the processed source, versioning information for the precompiler used, and a cryptographic hash (Keccak256) of the contents. This PEM format serves both for potential storage efficiency and as a verifiable artifact, allowing anyone to confirm that a given PEM file corresponds to a specific original source code by re-running the same precompiler version.
Following precompilation (or directly from the original source), the code enters the Compiler stage. This infrastructure is centered around the qvm-compiler Go application, which acts as an orchestrator. Based on the input source file extension or explicit flags, qvm-compiler identifies the language and invokes the corresponding language-specific compilation logic. Each supported language (e.g., Go, C++, Rust, Java, Python, JavaScript, etc.) has a dedicated Docker-based build environment. These environments contain the necessary toolchains (like tinygo, clang, rustc, javac), specific runtimes or interpreters where needed (like minijvm, gpython, QuickJS), and common build tools provided by a base buildtools image. A critical component included during compilation is the qan_proxy library, which provides the standardized interface for the compiled contract to interact with the blockchain environment (e.g., reading/writing state, initiating transactions). The ultimate output of the Compiler stage is a standard, self-contained ELF executable binary, ready for execution within the QVM.
The core runtime is provided by using QEMU-based virtualization. Initially, during the audit the project was using gokvm instead of QEMU-based hypervisor. When a contract execution is requested, QVM (QAN virtual machine) selects an idle VM and initiates the process. Each VM boots a highly customized, minimal Linux kernel, specifically patched to remove sources of non-determinism (like standard time sources or unseeded randomness). The VM's root filesystem is an initial RAM disk (initrd) containing the essential components for contract execution. This includes an /init process acting as a guest agent, essential libraries, a gRPC proxy for host communication, and crucially, the 3rd party execution sandbox component binary.. Communication between the host and the guest VM primarily occurs over virtual network connection using a gRPC protocol, facilitating the transfer of the contract binary, input data, environment variables (blockchain context), and handling interactive calls during execution.
Within the carefully controlled guest VM environment, the Hermit engine provides the final and most critical layer for ensuring determinism. The guest agent invokes Hermit to run the compiled ELF contract binary. Hermit acts as a deterministic process supervisor, intercepting all system calls made by the contract. It controls the execution flow, manages process/thread scheduling deterministically, replaces standard time and randomness system calls with deterministic implementations seeded by blockchain data (e.g., block hash, timestamp), and ensures that interactions with the virtual environment are perfectly reproducible. Any calls the contract makes to interact with the blockchain state (via the linked qan_proxy library) are translated into gRPC requests, passed through Hermit, the guest agent, VM, and finally handled by the host blockchain node, with results returned along the same path.
Upon completion, Hermit captures the contract's exit code, standard output, and standard error streams. These results are packaged and sent back to the host gokvm via the gRPC channel. The VM then returns the final execution result to the blockchain's core logic. This comprehensive, layered approach allows QVM to securely execute diverse smart contracts while guaranteeing the deterministic outcome required for blockchain consensus.
Risks
Compiler Toolchain Vulnerabilities: The system relies on numerous third-party language toolchains (Go, Clang, Rust, Java, Node/JS/TS, Python, etc.) packaged within distinct Docker images for the Precompiler and Compiler stages. Each toolchain represents an attack surface. Outdated or vulnerable versions within these images could potentially be exploited during the build phase, leading to compromised build environments or the generation of insecure contract binaries. This is a common risk in very complex projects. QANplatform's Response: QANplatform acknowledges that vulnerabilities in third-party toolchains are a broad, industry-wide challenge. Our primary technical mitigation is the requirement for a pre-committed hash of the final ELF binary to be included in the deployment transaction. If a compromised toolchain alters the build output, the resulting hash will not match the expected hash, causing the transaction to fail and protecting the network. Procedurally, we continuously monitor the security of our dependencies and update them as part of our standard maintenance and security practices.
Non-Deterministic Build Process: A significant risk arises from the current methodology of running the Compiler stages directly within standard Docker containers. Docker environments, while providing isolation, do not guarantee deterministic execution across different host machines or even between subsequent runs on the same machine. To ensure that the compilation step produces cryptographically identical outputs for the same source code across all validator nodes, these build tools would ideally need to be executed within a fully deterministic environment. QANplatform's Response: This risk is fundamentally addressed by QANplatform's core deployment mechanism. The expected hash of the final compiled ELF binary must be included in the deployment transaction itself. During the on-chain compilation, if the resulting binary's hash does not perfectly match this pre-committed hash, the transaction is rejected, and all associated gas fees are burned. This design ensures that only deterministically produced binaries that match the developer's intended output are accepted by the network, effectively neutralizing risks from potential compiler non-determinism.
Timing and Timeout Non-Determinism: Execution times for compilation and the final smart contract execution will inevitably vary depending on the hardware specifications and current load of the host machine (validator node). Relying on wall-clock timeouts introduces non-determinism, as a process might complete on a faster machine but fail on a slower one, leading to consensus failures. QANplatform's Response: To mitigate non-determinism arising from timing variations, QANplatform mandates that all validator nodes operate on homogenous hardware. This is a standard practice in high-performance blockchain networks to ensure consistent performance and execution times across the network. If a transaction still times out on a majority of nodes due to its complexity, it is collectively considered invalid by the network, thereby maintaining consensus.
Lack of Resource Limits and Timeouts in Build Stages: The compiler stages currently lack built-in, enforced timeouts or resource usage limits (CPU, memory). Malformed or maliciously crafted source code inputs could potentially cause these build processes to consume excessive system resources or enter infinite loops, presenting a potential Denial-of-Service (DoS) attack vector against validator nodes. QANplatform's Response: The build stages are executed with strict safeguards. Each compilation occurs within a physically isolated compute cluster, running in an ephemeral, unprivileged, and rootless containerd context. These environments have strict, built-in resource limits (CPU, memory) and timeouts that are enforced at the infrastructure level and tied directly to the transaction's pricing model. The cost of a deployment, and thus its resource allocation, is calculated based on factors like input source code and output binary size. If any build process exceeds its allocated resources or time limit, it is automatically terminated, and the transaction fails, preventing any single deployment from launching a Denial-of-Service (DoS) attack.
Findings
Code ― | Title | Status | Severity | |
|---|---|---|---|---|
| F-2025-9921 | Thread Race Condition and Resource Sampling | fixed | High | |
| F-2025-9920 | CPU/Memory Resource and Heap Variability | fixed | High | |
| F-2025-9919 | Hardware Feature and Configuration Variability | fixed | High | |
| F-2025-9918 | System State and /proc Sampling Variability | fixed | High | |
| F-2025-9917 | Thread Timing and Resource Exhaustion Variability | fixed | High | |
| F-2025-9916 | Process/Thread Race Condition and Timing Variability | fixed | High | |
| F-2025-9915 | Hardware Timing and TSC Measurement Variability | fixed | High | |
| F-2025-9914 | IPC and Output Ordering Variability | fixed | High | |
| F-2025-9913 | Uninitialized Memory Access Variability | fixed | High | |
| F-2025-9912 | Timer and Signal Handling Variability | fixed | High |
Appendix 1. Severity Definitions
Severity | Description |
|---|---|
Critical | Vulnerabilities that can lead to a complete breakdown of the blockchain network's security, privacy, integrity, or availability fall under this category. They can disrupt the consensus mechanism, enabling a malicious entity to take control of the majority of nodes or facilitate 51% attacks. In addition, issues that could lead to widespread crashing of nodes, leading to a complete breakdown or significant halt of the network, are also considered critical along with issues that can lead to a massive theft of assets. Immediate attention and mitigation are required. |
High | High severity vulnerabilities are those that do not immediately risk the complete security or integrity of the network but can cause substantial harm. These are issues that could cause the crashing of several nodes, leading to temporary disruption of the network, or could manipulate the consensus mechanism to a certain extent, but not enough to execute a 51% attack. Partial breaches of privacy, unauthorized but limited access to sensitive information, and affecting the reliable execution of smart contracts also fall under this category. |
Medium | Medium severity vulnerabilities could negatively affect the blockchain protocol but are usually not capable of causing catastrophic damage. These could include vulnerabilities that allow minor breaches of user privacy, can slow down transaction processing, or can lead to relatively small financial losses. It may be possible to exploit these vulnerabilities under specific circumstances, or they may require a high level of access to exploit effectively. |
Low | Low severity vulnerabilities are minor flaws in the blockchain protocol that might not have a direct impact on security but could cause minor inefficiencies in transaction processing or slight delays in block propagation. They might include vulnerabilities that allow attackers to cause nuisance-level disruptions or are only exploitable under extremely rare and specific conditions. These vulnerabilities should be corrected but do not represent an immediate threat to the system. |
Severity
- Critical
Description
- Vulnerabilities that can lead to a complete breakdown of the blockchain network's security, privacy, integrity, or availability fall under this category. They can disrupt the consensus mechanism, enabling a malicious entity to take control of the majority of nodes or facilitate 51% attacks. In addition, issues that could lead to widespread crashing of nodes, leading to a complete breakdown or significant halt of the network, are also considered critical along with issues that can lead to a massive theft of assets. Immediate attention and mitigation are required.
Severity
- High
Description
- High severity vulnerabilities are those that do not immediately risk the complete security or integrity of the network but can cause substantial harm. These are issues that could cause the crashing of several nodes, leading to temporary disruption of the network, or could manipulate the consensus mechanism to a certain extent, but not enough to execute a 51% attack. Partial breaches of privacy, unauthorized but limited access to sensitive information, and affecting the reliable execution of smart contracts also fall under this category.
Severity
- Medium
Description
- Medium severity vulnerabilities could negatively affect the blockchain protocol but are usually not capable of causing catastrophic damage. These could include vulnerabilities that allow minor breaches of user privacy, can slow down transaction processing, or can lead to relatively small financial losses. It may be possible to exploit these vulnerabilities under specific circumstances, or they may require a high level of access to exploit effectively.
Severity
- Low
Description
- Low severity vulnerabilities are minor flaws in the blockchain protocol that might not have a direct impact on security but could cause minor inefficiencies in transaction processing or slight delays in block propagation. They might include vulnerabilities that allow attackers to cause nuisance-level disruptions or are only exploitable under extremely rare and specific conditions. These vulnerabilities should be corrected but do not represent an immediate threat to the system.
Appendix 2. Scope
The scope of the project includes the following components from the provided repository:
Scope Details | |
|---|---|
| Repository | Encrypted zip archive with gokvm, hermit, precompiler, and compiler |
| Commit | Initial: c7feafc7ccd521656428d9a8e825bcbb84cc6a8ee9f2a658cad593c3d9613dc8 |
| Final: 9f032cb65887a646aa68df04a96800cf7e009755e1e06ea5a5a25fea16827ee5 |
Scope Details
- Repository
- Encrypted zip archive with gokvm, hermit, precompiler, and compiler
- Commit
- Initial: c7feafc7ccd521656428d9a8e825bcbb84cc6a8ee9f2a658cad593c3d9613dc8
- Final: 9f032cb65887a646aa68df04a96800cf7e009755e1e06ea5a5a25fea16827ee5
Components in Scope
A primary scope of the audit is to determine if the QVM runtime can be abused to cause non-deterministic output given any output binary from any of the supplied compilers and an arbitrarily chosen state.
The main scope of compiler and pre-compiler pentesting is assessing if there are situations in which:
The supplied pre-compilers produce non-deterministic output from the same source code.
The supplied compilers can produce non-deterministic output binaries given any output from the language-relevant pre-compiler.
Assumptions:
Input is valid source code for the given programming language that the pre-compiler intended to handle.
Compilers are only fed the output of the pre-compilers as their input.
QVM runtime is only fed the output of the compilers as its input.