Chains
Vyper contract audit: compiler evidence, tool limits and application scope
Compiler assurance and application assurance answer different questions. A Vyper contract audit must connect the source, compiler settings and deployed behavior while checking language-specific protections and known advisories.

Key facts
- Compiler index
- 18 linked review entries at the measured revision
- Limited-review marker
- 10 of 18 filenames explicitly say limited review
- Formats
- 17 PDF entries and 1 Markdown competitive report
- Tool boundary
- Slither supports Vyper; Echidna documents limited support
Language differences that matter to the audit
A Vyper contract audit must identify the compiler and application behavior being reviewed, rather than treating Vyper as Solidity with different syntax. Language restrictions can make some code paths easier to inspect, but the generated bytecode, dependency behavior and economic assumptions still require evidence.
Vyper's design documentation excludes features such as Solidity-style modifiers, class inheritance and inline assembly to improve readability and constrain misleading control flow. That design does not make the language immune to compiler bugs or application errors. Nor does the absence of class inheritance mean a project has no modules, imports or external dependencies.
Start with visibility and mutability.
The opened documentation distinguishes external functions, internal functions and deployment code. A view function can read state without changing it, while a mutable function may update state. The review should establish the actual externally reachable surface and how imported code participates in it.
Nonreentrancy behavior is version-specific.
Current documentation describes a global lock shared by protected functions and a file-scoped pragma available beginning with version 0.4.2. That pragma can enable protection for external functions and eligible public getters in the file. It is off by default in the opened reference, so the compiler version alone does not prove it was enabled.
Inspect exceptions and imports.
The documentation states that imported files retain their own nonreentrancy behavior and that explicit reentrant declarations can permit a particular path. A source review should therefore record the pragma and decorators where they actually apply. A claim that the whole project is nonreentrant needs more than one protected entry point.
| Property | What to inspect | Unsupported shortcut |
|---|---|---|
| Entry-point visibility | External, internal and deployment declarations | Assuming every function is externally reachable |
| Mutability | State reads, writes and external-call constraints | Treating a view result as economically trustworthy |
| Lock behavior | Compiler version, pragma and decorators | Assuming a language-wide protection is always on |
| Dependencies | Imports, modules and external interfaces | Equating no class inheritance with no dependencies |
| Generated behavior | Build settings and runtime bytecode | Treating source readability as compiler correctness |
Vyper design principles and the function and nonreentrancy reference support these distinctions.
Tooling gaps: verify the supported operation, not just the language label
The current Slither README explicitly describes support for both Solidity and Vyper.
Calling it a Solidity-only tool would be inaccurate. The useful question is narrower: does the installed version support your compiler output, project structure and the particular analysis being requested?
Echidna's README lists limited Vyper support.
That is a reason to verify the exact harness and integration, not to report that all Vyper fuzzing is impossible. A tool can accept compiled bytecode while providing different source mapping or language-specific analysis support. Preserve the behavior actually exercised by the run.
Titanoboa provides a Vyper-oriented execution environment.
Its README explains that it uses Vyper as a library to compile source and runs bytecode through an instrumented EVM implementation. That offers useful introspection, but the audit still needs to identify the execution rules, compiler configuration and any instrumentation assumptions relevant to the result.
A successful installation is not a successful security check.
Record which files compiled, which analyses ran and which portions were skipped or unsupported. A process that exits without findings after failing to load the target does not establish a clean result. Keep setup failures separate from contract findings.
| Tool | Documented capability or limit | Evidence to request from the engagement |
|---|---|---|
| Slither | Solidity and Vyper static-analysis framework | Version, target compilation and detectors actually run |
| Echidna | README lists limited Vyper support | Working harness and the exact properties exercised |
| Titanoboa | Vyper compilation with instrumented execution | Compiler, execution configuration and reproducible tests |
| Vyper compiler | Layout and multiple output formats | Pinned settings and generated artifacts |
Slither's current README, Echidna's documented limitations and Titanoboa's architecture description are the primary references for those claims.
For a multi-language protocol, review the interfaces between components.
A Vyper contract can depend on an external asset or adapter implemented in another language. Tests should preserve the actual calling and return-value expectations rather than replacing every dependency with a permissive mock.
Code coverage also needs interpretation. Executing a line can establish that a test reached it, but it does not show that the relevant adversarial state was explored. Pair coverage with named properties for accounting, authorization and failure handling. An unsupported analyzer should create a documented evidence gap and a replacement review method, not an unexplained omission.
This article did not execute these tools against a production contract. The descriptions are grounded in their opened documentation. A commissioned audit should provide its own commands, versions and outputs for the actual candidate. That distinction keeps a tooling recommendation from becoming a claim of tested compatibility.
The 2023 compiler incident: match the affected build, not the source appearance
The Vyper advisory GHSA-5824-cm3x-3c38 documents a reentrancy-lock allocation problem in compiler versions 0.2.15, 0.2.16 and 0.3.0. The issue gave functions separate locks even when they used the same named key. A source reader could see the intended shared protection while the generated behavior failed to supply it.
The advisory's conditions matter. It describes a primary function using a named nonreentrancy key, an external call before relevant effects and another function whose behavior can be affected by the inconsistent state. An affected compiler version is therefore an exposure indicator to investigate; it is not sufficient by itself to prove that every compiled contract has an exploitable path.
The advisory identifies 0.3.1 as the patch for this issue. That statement must not be expanded into a recommendation that this old version is the current safest compiler or free from all known bugs. Compiler selection should consider the current advisory list, release requirements and the target chain.
A compiler release does not change already deployed bytecode. A project must identify the artifacts built with an affected compiler and determine which of them expose the relevant path. The available response then depends on deployment authority, migration options and the integrations that consume the contract.
| Evidence | Question | Required distinction |
|---|---|---|
| Compiler version | Was the deployed artifact built by an affected version? | A repository setting may differ from the actual build |
| Lock declarations | Which functions were intended to share protection? | Source intent and emitted behavior can differ |
| External-call sequence | Can control leave before the relevant state is complete? | A version match alone is not an exploit |
| Cross-function path | Can the callback use inconsistent state elsewhere? | Same-function testing may miss the relevant route |
| Deployment options | Can the affected artifact be replaced or retired? | Publishing a compiler patch does not patch production |
The Vyper security advisory provides the affected versions and conditions. The reentrancy test matrix shows how to map those conditions to callback paths.
Preserve negative results as well as confirmed exposure. A contract may use an affected compiler but lack the required callback path under its supported dependencies. That conclusion needs a bounded analysis of those dependencies and configuration, not an assumption that the decorator must work.
Historical code samples also need a version label. Earlier Vyper releases used named keys, while the opened current documentation describes a global lock. Mixing the old annotation syntax with a current-language explanation can make a review checklist internally inconsistent. Keep the version and the property together in both tests and report prose.
Our compiler-review inventory: 18 entries with different scopes
We inventoried every report entry under a year heading in the compiler-maintained Vyper audit index at a pinned revision. The index contains 18 entries across the listed years. Ten filenames explicitly identify a limited review. Counting all entries as independent full-compiler audits would therefore overstate what the index describes.
Method
- Source
- Vyper audit index
- Retrieved
- Selection
- All linked report entries under year headings in the pinned README. Introductory firm links are excluded.
- Unit
- One index entry, including the competitive report and limited reviews.
- Scope signal
- The literal limited_review filename marker. Absence of that marker is not proof of full coverage.
- Revision
- The survey output retains the exact repository commit and raw index text.
Results
| Year or attribute | Entries | Denominator |
|---|---|---|
| 2022 | 1 | 18 index entries |
| 2023 | 8 | 18 index entries |
| 2024 | 6 | 18 index entries |
| 2025 | 3 | 18 index entries |
| Filenames marked limited review | 10 | 18 index entries |
| PDF report links | 17 | 18 index entries |
The remaining entry is a Markdown competitive-audit report. The index names ChainSecurity, OtterSec, Statemind, Anatomist and CodeHawks across its entries. These are publisher or platform labels in the index, not a count of independent teams that reviewed every compiler subsystem.
Limits
- The inventory counts the index, not every review that may exist elsewhere.
- Report entries can cover a feature, release candidate, fix review or limited subsystem.
- The census did not execute compiler tests or independently reproduce report findings.
- Listed years describe the index entries and do not establish the latest compiler release date.
Reproduction uses seo/research/vyper-audit-index-survey.py; its dated output is seo/research/vyper-audit-index-survey-2026-09-05.json. These files remain in the repository and are not published as downloads. The output preserves source responses, retrieval outcomes and the selection rules for later verification.
Audit scoping for Vyper: separate compiler and application evidence
The application scope should identify the source revision, compiler build, optimization mode and target execution rules. Vyper's compilation documentation exposes settings and outputs relevant to that record. A source file without its build context is insufficient for comparing a reviewed candidate with deployed runtime bytecode.
Preserve both deployment and runtime artifacts. Constructor or deployment arguments can install a different administrator or dependency even when the runtime source looks familiar. A bytecode comparison should explain the metadata and configuration it accounts for rather than asserting equivalence from a superficial text match.
Optimization belongs in the record. The compiler documentation describes modes that prioritize code size or gas differently. The audit does not need to assume an optimizer is faulty to require a reproducible build. It needs the settings that produced the actual behavior under review.
Review storage layout where state persists across a transition. The compiler can emit layout information, but a structural output does not prove that a migration preserves application meaning. Existing balances, lock state and privileged roles may need explicit before-and-after assertions. This is especially relevant when a dependency or compiler change alters storage assumptions.
Separate compiler assurance from application assurance in the report. An audit of a compiler subsystem can support confidence in that subsystem under its scope. It does not evaluate your collateral policy, oracle integration or administrator permissions. Conversely, an application audit may rely on a specified compiler without re-auditing the compiler itself.
| Artifact | Purpose | Acceptance question |
|---|---|---|
| Source and imports | Define the candidate implementation | Can the reviewer reconstruct the exact project? |
| Compiler and settings | Define generated behavior | Does the build reproduce the expected artifacts? |
| Deployment configuration | Define installed authority and dependencies | Does production match the reviewed setup? |
| Property tests | Define intended accounting and authorization | Were the meaningful adversarial paths exercised? |
| Advisory assessment | Define known compiler exposure | Are affected conditions present in the deployment? |
| Residual-risk record | Define the assurance boundary | Which compiler or integration assumptions remain? |
Vyper compilation and layout documentation explains the build evidence. The upgrade review guide covers state transitions when the deployment supports replacement.
- Source semantics
- Imports and protections.
- Compiler artifact
- Pinned settings.
- Deployed behavior
- Configuration and tests.
For an immutable deployment, record the response that remains possible if a compiler issue is confirmed. It may involve restricting an integration, migrating users or retiring an affected component. The audit should not promise an in-place repair when no authorized replacement path exists. Establish the practical options before a production incident forces the decision.
Firms with Vyper experience: request the relevant artifact
The compiler-maintained index names several organizations and a competitive platform with Vyper review work. Read the individual scope before deciding whether that experience matches your need. A limited compiler review, a storage-layout assessment and an application audit are different evidence.
ChainSecurity's opened Curve Stablecoin report provides an application-level example. It lists Vyper compiler versions against the reviewed commits and identifies in-scope files. The report also states limitations, including that it did not review the economic soundness of the contracts. That boundary is relevant when a buyer is seeking an economic-design assessment in addition to code review.
Use the report to sharpen the request. Ask the candidate team for a Vyper engagement with comparable compiler, dependency and application complexity. Request an explanation of which tools they ran, what their tests asserted and how they handled known compiler advisories. A language name on a services page supplies less evidence than a scoped report.
A general Solidity report archive is a weak substitute for language-specific evidence. Request the Vyper source boundary, compiler assumptions and tool results from the actual engagement. The compiler index and Curve report provide different direct artifacts: one inventories compiler reviews, while the other identifies an application scope. Use that distinction when comparing proposals. A missing language keyword in another report would not establish that the firm lacks Vyper experience, just as a language keyword alone would not establish the coverage you need.
ChainSecurity's Curve Stablecoin assessment and Vyper's security policy establish the application and compiler evidence boundaries.
Use the audit-company analysis hub and Halborn analysis for provider context, then specify the required language evidence in the audit request. The chosen team should commit to the actual compiler and application scope.
The final acceptance record should make a simple comparison possible: the reviewed source and build settings produced the deployed artifact, and the report's conclusions apply to that configuration. Where that connection is not established, name the missing evidence. A compiler audit count cannot fill the gap.
For a compiler upgrade, preserve a comparison of the old and new build outputs alongside the regression results. Explain expected differences before attributing every bytecode change to an error. The review question is whether the new artifact preserves the required behavior under the intended execution rules, with any deliberate changes documented.
A language-specific test harness should also record which external dependencies it simulates. Instrumentation can make a failure easier to inspect while still leaving real token behavior or remote state outside the experiment. Keep those limits in the report so a reader can distinguish a reproduced application property from a broader deployment claim.
Frequently asked questions
Does a Python-looking syntax mean Vyper can be reviewed as ordinary Python?
No. The contract's language rules, compilation and EVM execution determine its behavior. Familiar syntax does not transfer Python runtime assumptions to a deployed contract.
Can a report covering a release candidate be treated as coverage of the final compiler?
Compare the reviewed candidate with the final release and identify changes outside the report. A shared version family does not establish that every later change received the same review.
Can verified source on an explorer establish the compiler executable used by CI?
Explorer verification and build-system provenance answer different questions. Retain the compiler distribution, checksum and build record used in the review, then compare its output with the verified deployment. A displayed version string alone does not establish the executable provenance.