Skip to main content
Background Image
  1. Blog/

Debtmap Adds Go and Solidity Support for Web3 Code Review

Author
Glen Baker
Building tech startups and open source tooling
Table of Contents

Debtmap started from a practical thesis: bugs tend to correlate with certain kinds of code.

Not perfectly. Not mechanically. But enough to be useful.

Complex functions are easier to misunderstand. Frequently updated files are places where design pressure is still active. Historical bug hot spots are worth treating with suspicion. Low test coverage makes changes riskier. Code that developers avoid touching often has reasons for being avoided.

Debtmap tries to combine those signals into a ranked map of where mistakes are most likely to hide.

That prioritization problem is especially sharp in Web3.

Smart contract teams already have strong tools for specific classes of work. Slither is great for Solidity static analysis. Foundry is great for fast tests, fuzzing, and invariant checks. Echidna and Medusa can pressure state machines. Formal methods can prove properties when the economics justify the effort.

Debtmap is not trying to replace those tools.

It answers a different question: where should human eyes go first?

Recent Debtmap releases added initial Go support and Solidity support. That matters because many Web3 systems are not just contracts. They are contracts plus indexers, relayers, keeper bots, bridges, backend services, CLIs, monitoring jobs, deployment scripts, and offchain infrastructure. A security review that only looks at contracts/ can miss risk sitting in the code that signs, submits, watches, or reacts to transactions.

Debtmap now has enough language coverage to start mapping that mixed surface area, which makes it more useful for initial recon before the deeper security work begins.

I should be clear about my own position here: I am not a professional smart contract auditor. I have found some medium and low severity bugs in competitions and bug bounty work, and I spend a lot of time thinking about how to aim limited review time. So the claim I want to make is modest: Debtmap looks useful as a recon aid because its ranking signals appear to line up with places where bugs tend to be found.

The Correlation Thesis
#

A Solidity function can look harmless in isolation and still be a bad audit target to ignore.

Maybe it has several nested branches around accounting state. Maybe it makes an external call before updating internal balances. Maybe it has no direct tests. Maybe the same file has changed five times during incident fixes. Maybe the contract is part of an upgrade path and depends on inherited behavior from another file.

Security work is full of those “maybe” signals. None of them prove a bug. Together, they tell you where review time is likely to pay off.

Debtmap combines several signals into one ranked view:

  • Complexity: cyclomatic complexity, cognitive complexity, nesting, and function length
  • Coverage: whether risky code is backed by tests when coverage data is available
  • Git history: churn, bug-fix history, and author spread when context analysis is enabled
  • Coupling: imports, inheritance, call relationships, and dependency pressure
  • Language-specific advisories: patterns that deserve review in the language being analyzed

The central idea is correlation. Complexity, historical bug hot spots, frequently updated files, and test coverage define the parts of a codebase where mistakes are more likely to hide. They also define the places where developers are often least eager to make casual changes.

For smart contracts, that priority model is useful because the highest-risk code is often not the code with the loudest single lint warning. It is the code where complexity, low test confidence, and change history overlap.

I also use Debtmap in my own projects to guide code quality work with agentic workflows: find the worst-ranked areas, fix them iteratively, then run the map again. That is a separate post. For Web3 security, the more immediate value is recon: figuring out where to put human attention first.

Solidity Support
#

Debtmap can now parse Solidity files and include them in normal project analysis:

cargo install debtmap
debtmap analyze ./contracts --languages sol

Or analyze a mixed repository:

debtmap analyze . --languages rust,python,javascript,typescript,go,solidity

The initial Solidity support includes:

  • .sol file discovery and language routing
  • Tree-sitter parsing
  • Contract, interface, library, modifier, constructor, fallback, and receive detection
  • Cyclomatic and cognitive complexity metrics
  • Function length and nesting analysis
  • Import and inheritance extraction, including Foundry remapping resolution
  • Typed cross-contract and inherited-call resolution
  • NatSpec completeness checks for public and external functions
  • State-read, state-write, external-call, value-transfer, and purity signals
  • Foundry test detection for patterns like *.t.sol and forge-std/Test.sol
  • Smart-contract-specific advisory patterns

The advisory patterns are intentionally framed as review prompts, not proof of exploitability. Current examples include:

  • tx.origin usage
  • Unchecked low-level calls
  • External calls before state updates
  • delegatecall
  • selfdestruct
  • Inline assembly
  • Unbounded loops
  • Missing access control signals
  • Large contracts
  • Hardcoded addresses
  • Floating pragmas

That distinction matters. A delegatecall is not automatically a vulnerability. A floating pragma is not automatically exploitable. An external call before a state update may be safe when guarded correctly.

But these are the kinds of patterns auditors usually want to inspect in context. Debtmap’s job is to put them near the top when they also sit inside complex, under-tested, frequently changed code.

Where Go Fits
#

Go support is useful for the offchain side of Web3 systems.

Plenty of protocol risk lives outside Solidity:

  • Relayers that decide which messages to submit
  • Indexers that reconstruct protocol state from events
  • Keepers that trigger liquidations, rebalances, or maintenance flows
  • Wallet services and signing infrastructure
  • Bridge services and validator software
  • CLIs and deployment tools used by operators

Debtmap’s Go analyzer handles packages, imports, functions, receiver methods, same-package and module-local calls, complexity, generated-code handling, and Go-specific debt signals. It also preserves call relationships for instantiated generic functions when they can be resolved statically.

That means a team can ask one practical question across more of the system:

debtmap analyze . --languages go,solidity --context

The output will not tell you “this bridge is safe” or “this contract is vulnerable.” It gives you a ranked map of where complexity and historical risk have accumulated.

For an auditor, that is useful before the deep work starts. It turns a mixed repository into a review queue instead of a flat list of files.

A Better First Pass for Audits
#

When I review a codebase, I do not want to start with the most famous file or the biggest file. I want to start where bug probability and impact plausibly overlap.

Debtmap is useful here because it does not require you to know the codebase yet. It gives you an initial hypothesis about where bugs may cluster, then you can accept, reject, or refine that hypothesis as you read.

For Solidity and Web3 projects, a useful first pass looks like this:

# Contracts only
debtmap analyze ./contracts --languages sol --format markdown --top 20

# Contracts with git history context
debtmap analyze ./contracts --languages sol --context --format markdown --top 20

# Mixed protocol repo
debtmap analyze . --languages go,solidity --context --format markdown --top 30

If coverage data is available, include it:

debtmap analyze ./contracts --languages sol --lcov coverage.lcov --context

For Foundry projects, this pairs naturally with coverage generated from the test suite. Debtmap can then rank complex contract logic differently depending on whether that logic is exercised by tests.

That is the core value: a 30-line function with no tests and a history of bug fixes should not be treated the same as a 30-line function with stable history and strong coverage.

A Small Public Check
#

Rather than leave this as pure speculation, I looked at one public competition report: Code4rena’s Sequence Findings & Analysis Report.

The report says the contest reviewed the C4 Sequence repository, pulled from Sequence’s upstream wallet-contracts-v3 repo at commit 4c0a98259624b80ac22385e40f83a2145e8e33e2. The final report includes 2 high severity findings and 4 medium severity findings, with source links into the contest repo.

I checked out the C4 snapshot at b0e5fb15bf6735ec9aaba02f5eca28a7882d815d and ran Debtmap 0.21.2 without coverage:

debtmap analyze ./src --languages sol --format json

This is not the full Debtmap model. The C4 snapshot is a contest repository, so it does not carry the normal upstream git history that would make churn and historical bug-hotspot analysis more meaningful. I also did not include coverage data in this comparison. This is mostly a check of the static ranking: complexity, structure, and Solidity advisory signals.

Even with that limitation, the overlap was interesting.

Sequence Code4rena Debtmap hit-rate chart

The contest src/ tree had 49 Solidity files. The high and medium findings cited 9 unique source files. Debtmap’s top 8 ranked items touched 4 of those 9 H/M finding files:

Debtmap rankFileWhy it matters in the report
1src/modules/Calls.solCited in H-02
5src/extensions/sessions/SessionManager.solCited in M-01
6src/modules/auth/BaseSig.solCited in H-01
8src/extensions/sessions/SessionSig.solCited in H-02 and M-01

For comparison, a random top 8 drawn from 49 files with 9 target files would have an expected overlap of about 1.5 files. That is what the red baseline in the chart represents.

The same run also ranked PermissionValidator.sol second, which appears in the report’s low/non-critical section. That does not prove much by itself, but it is directionally consistent with the idea that complex review targets and reported issue locations are not randomly distributed.

This is still only one case study. It does not prove that Debtmap predicts bugs. It also does not measure the full version of the thesis, because the contest snapshot weakens the git-history signal and I did not include coverage. But it is a better starting point than vibes: a public repo, a public report, a reproducible command, and a visible overlap between Debtmap’s first-pass queue and the files where researchers reported issues.

How This Helps Recon
#

Early review time is expensive because the repository is still unfamiliar. You are building a mental model while also trying not to miss important risk.

Debtmap helps turn that first pass into a narrower set of questions:

  • Which contracts should get manual review first?
  • Which functions combine complex control flow with weak coverage?
  • Which files changed often enough to deserve suspicion?
  • Which dependencies and inherited contracts shape the risk surface?
  • Which offchain Go components are complicated enough to influence protocol safety?

The markdown output is also useful for review notes because it gives you a compact, ranked set of targets:

debtmap analyze . --languages go,solidity --context --format markdown --top 20

That is not an audit plan by itself. It is a first map. It tells you where to start asking better questions.

This is especially useful in the early hours of an audit, when the repository is still unfamiliar and the most expensive mistake is spending too much time in low-risk code.

Debtmap does not make the security judgment. It makes the queue.

The Important Caveat
#

Solidity support is still young compared with Debtmap’s more mature Rust and TypeScript analysis. The current Solidity analyzer is useful for single-file and project-level analysis, complexity scoring, generic debt detection, dependency extraction, and heuristic security advisories.

It is not formal verification. It is not symbolic execution. It is not a replacement for Slither, Foundry fuzzing, invariant testing, or manual review.

That is by design.

Debtmap is a prioritization tool. For Web3 security, prioritization is valuable because the review surface is large and time is finite. The point is to focus attention sooner on the code where multiple risk signals converge.

Try It
#

cargo install debtmap

# Solidity contracts
debtmap analyze ./contracts --languages sol

# Go and Solidity together
debtmap analyze . --languages go,solidity --context

# Markdown output for review notes
debtmap analyze . --languages go,solidity --context --format markdown --top 20

Links:

Smart contract security is not short on tools. What it often lacks is a clear first map of where to spend attention. With Go and Solidity support, Debtmap is starting to become that map for Web3 repositories.

More to come.

Related

Debtmap 0.16.7: Faster Code Debt Analysis for Real Repositories
Debtmap Re-adds JavaScript and TypeScript Support
Refactoring a God Object Detector That Was Itself a God Object
Automating Documentation Maintenance with Prodigy: A Real-World Case Study
Pure Core, Imperative Shell in Rust with Stillwater
Stillwater 1.0: Pragmatic Effect Composition and Validation for Rust