SEBI – Stylus Execution Boundary Inspector | Final Report & Grant Close-Out

Overview

This is the final report and close-out for SEBI (Stylus Execution Boundary Inspector), submitted under the Arbitrum One Developer Tooling Program (Stylus 3.0).

The idea behind SEBI is pretty simple: when you’re building a Stylus contract, there’s currently no lightweight way to check whether your compiled WASM artifact has execution-boundary issues before you deploy. Things like unbounded memory growth, dynamic dispatch via indirect calls, or loop structures that can lead to unpredictable execution are basically invisible until you’re either running on-chain or going through a full audit. SEBI fills that gap by doing a static, fully offline inspection of the compiled artifact and telling you what it finds — deterministically, without touching chain state.

All three milestones are done. Everything is publicly accessible at this repo https://github.com/Qeyphen/sebi.


Delivered Scope vs. Proposal

Milestone Scope Status Grant Amount
M1 – Core Static Analysis Engine WASM parsing, signal extraction, rule evaluation, classification, CLI :white_check_mark: Complete $7,875
M2 – Reporting, CI Integration & Real-World Validation JSON schema, human-readable output, GitHub Actions CI, OpenZeppelin validation :white_check_mark: Complete $2,100
M3 – Final Report & Close-Out Written summary, limitations, lessons learned :white_check_mark: Complete $1,125
Total $11,100

What Was Built

SEBI is a Rust workspace with two crates: sebi-core (the analysis library) and sebi-cli (the command-line tool). You point it at a .wasm file, and it gives you back a structured report telling you what it found and how it classified the artifact.

What it does:

  • Parses WASM binaries offline and inspects all relevant sections (memory, imports, exports, functions)

  • Scans every function body for three key instruction-level signals: memory.grow, call_indirect, and loop

  • Extracts 16+ structured signals across artifact, module, memory, and instruction categories

  • Evaluates those signals against a 5-rule explainable catalog and outputs a SAFE / RISK / HIGH_RISK verdict

  • Produces byte-for-byte identical JSON output across repeated runs — no timestamps, sorted arrays, stable hashing

  • Returns CI-ready exit codes: 0 = SAFE, 1 = RISK, 2 = HIGH_RISK

The test suite has 127 passing tests across unit, integration, and CLI categories.


Execution-Boundary Signals & Rule Behavior

Signals extracted per artifact:

Category Signals
Artifact size_bytes, SHA-256 hash
Module function_count, section_count
Memory memory_count, min_pages, max_pages, has_max
Instructions has_memory_grow, memory_grow_count, has_call_indirect, call_indirect_count, has_loop, loop_count
Imports/Exports import_count, export_count, detailed inventories

Rule catalog (v0.1.0):

Rule ID Description Severity Trigger
R-MEM-01 Missing declared memory maximum MED has_max == false
R-MEM-02 Runtime memory growth detected HIGH has_memory_grow == true
R-SIZE-01 Large WASM artifact MED size_bytes > 200,000
R-LOOP-01 Loop constructs detected MED has_loop == true
R-CALL-01 Dynamic dispatch detected HIGH has_call_indirect == true

Classification:

  • SAFE — nothing triggered

  • RISK — at least one MED rule, no HIGH

  • HIGH_RISK — at least one HIGH rule


Real-World Validation

To make sure SEBI actually works against real production contracts and not just hand-crafted test fixtures, I ran it against the full OpenZeppelin Rust Contracts for Stylus repository — 64 compiled WASM artifacts in total.

The results were pretty informative:

  • All 64 contracts triggered R-MEM-01. This is expected — the Stylus toolchain doesn’t set a WASM memory maximum by default, so every artifact will hit this rule. It’s a toolchain-level structural property, not something individual developers are doing wrong.

  • 32 contracts (debug builds) came back HIGH_RISK, triggering R-MEM-02, R-CALL-01, and R-LOOP-01. Debug builds retain more complex instruction patterns that the optimizer strips out.

  • 32 contracts (release builds) came back RISK with only R-MEM-01. The Rust compiler eliminates dynamic dispatch, memory growth, and loop constructs in optimized output, which is exactly what you’d expect.

This was a useful sanity check. SEBI correctly differentiates between debug and release profiles, runs fully offline, and behaves consistently across the full contract set.


CI Integration

There’s a complete GitHub Actions workflow at examples/sebi-ci.yml. It auto-discovers all cdylib crates in your workspace, compiles them to WASM, runs SEBI on each one, embeds the git commit SHA for traceability, and fails the job if anything comes back RISK or HIGH_RISK. Flagged contracts surface as ::error annotations in the PR UI, and all JSON reports are uploaded as CI artifacts regardless of outcome.

Getting it into a project is just:

mkdir -p .github/workflows
cp examples/sebi-ci.yml .github/workflows/sebi.yml

No RPC, no chain access, no configuration needed.


Limitations and Non-Goals

Worth being upfront about what SEBI is and isn’t:

  • It doesn’t execute WASM or estimate gas. It’s purely structural — it looks at what instructions and sections are present, not what they do at runtime.

  • A HIGH_RISK result doesn’t mean a contract is broken. It means structural patterns with execution-boundary implications were found. Whether that’s actually a problem depends on the contract’s intent. SEBI surfaces the signal; a developer or auditor still has to interpret it.

  • R-MEM-01 will fire on essentially every Stylus contract right now because the toolchain doesn’t emit a memory maximum by default. That’s expected behavior and not something SEBI can work around — it’s a property of how Stylus compiles today.

  • Multi-memory and component model artifacts aren’t fully analyzed. SEBI handles standard WASM MVP modules. If it encounters something outside that, it emits a warning but won’t produce a complete analysis.

  • Rule thresholds are conservative and MVP-grade. The 200 KB threshold for R-SIZE-01 was chosen to be permissive enough to avoid false positives on real contracts while still flagging genuinely large artifacts. It may need tuning as the ecosystem grows.


Deliverables Index

Deliverable Location
Core analysis library crates/sebi-core/
CLI binary crates/sebi-cli/
JSON report schema docs/SCHEMA.md
Rule catalog docs/RULES.md
User documentation README.md
WAT/WASM test fixtures crates/sebi-core/tests/fixtures/
CLI WASM fixtures crates/sebi-cli/fixtures/
CI integration example examples/sebi-ci.yml
Test suite (127 tests) cargo test --workspace

Closing

SEBI does what it set out to do: give Stylus developers a fast, offline way to see execution-boundary properties in their compiled contracts before deployment. It’s not a security auditor and it’s not a substitute for review — but it fills a real gap in the current tooling landscape by making these structural signals visible early, in CI, without any chain dependency.

Thanks to the Arbitrum Foundation and DAO for supporting this. The project is open, documented, and ready for anyone in the ecosystem to use or build on.


SEBI — Stylus Execution Boundary Inspector | Grant Close-Out | April 2026