Back to Security & Vulnerability Analysis

ruzzy

Rubyfuzzingsecurity testinglibFuzzercode qualitymemory safetyC extensionsvulnerability detection
⭐ 5.7kπŸ“„ CC-BY-SA-4.0πŸ•’ 2026-06-15Source β†—

Install this skill

npx skills add trailofbits/skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Ruzzy is a coverage-guided fuzzer tailored for the Ruby ecosystem, built upon the libFuzzer foundation. It provides critical security testing capabilities for both interpreted Ruby logic and native C extensions. By instrumenting the Ruby runtime, it identifies memory corruption, undefined behavior, and logical flaws that standard unit tests frequently miss. The tool requires specific environment configurations, such as LD_PRELOAD modifications and Clang-based compiler flags, to integrate correctly with the Ruby interpreter's memory management. It is primarily built for Linux environments and handles the complexity of tracing Ruby execution to map code paths, allowing developers to uncover vulnerabilities in gems that interface with low-level libraries. Ruzzy functions as a bridge between high-level Ruby code and the performance-oriented fuzzing capabilities provided by modern sanitizers.

When to Use This Skill

  • β€’Identifying buffer overflows in Ruby gems with complex C extensions
  • β€’Detecting memory leaks or invalid memory access in native parser libraries
  • β€’Fuzzing Ruby-based protocol implementations to find crashes in input parsing
  • β€’Testing custom Ruby extensions for undefined behavior under mutation testing

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œHow do I fuzz my Ruby C extension for memory safety?
  • β€œFind bugs in my Ruby gem using libFuzzer
  • β€œHow to set up Ruzzy for coverage-guided testing in Ruby?
  • β€œIdentify memory corruption in Ruby gems
  • β€œWrite a harness to test Ruby code with Ruzzy

Pro Tips

  • πŸ’‘Integrate Ruzzy into your CI/CD pipeline for continuous security testing of your Ruby projects.
  • πŸ’‘Prioritize fuzzing efforts on critical or high-risk components, particularly Ruby C extensions, to maximize impact.
  • πŸ’‘Combine Ruzzy with other security tools like static analysis for a multi-layered approach to vulnerability detection.

What this skill does

  • β€’Coverage-guided fuzzing for pure Ruby code using tracer scripts
  • β€’Direct memory safety testing for native Ruby C extensions
  • β€’Integration with AddressSanitizer (ASAN) to detect heap corruption
  • β€’Support for arbitrary input generation to explore code branches
  • β€’Instrumentation-based path discovery within the Ruby VM

When not to use it

  • βœ•Standard functional testing of business logic where crash detection is not the primary goal
  • βœ•Environments where native Clang compilation and LD_PRELOAD instrumentation are not supported
  • βœ•Fuzzing high-level Rails controllers where business logic dominates over memory-safe code paths

Example workflow

  1. Install Clang and Ruzzy using the required environment variable overrides for CC and CXX
  2. Define a test_one_input lambda in a Ruby harness file
  3. For pure Ruby targets, create a tracer script to wrap the harness
  4. Export ASAN_OPTIONS to configure memory sanitizer behavior
  5. Run the target with LD_PRELOAD pointing to the Ruzzy ASAN library
  6. Analyze crash logs and code coverage output to identify the faulting input

Prerequisites

  • –Linux x86-64 or AArch64/ARM64
  • –Clang compiler version 14.0.0 or newer
  • –Ruby development headers

Pitfalls & limitations

  • !Failing to catch Ruby exceptions in the harness will terminate the fuzzer process prematurely
  • !Complex Ruby gems may require specific sanitizer-enabled recompilation to be fuzzable
  • !Incorrectly configured LD_PRELOAD paths will cause the fuzzer to fail silently or crash immediately

FAQ

Why do I need a tracer script for pure Ruby but not for C extensions?
Pure Ruby code requires a tracer to track execution paths within the interpreter, whereas C extensions can be instrumented directly via compiler flags.
Can I use Ruzzy on macOS?
Ruzzy is native to Linux. For macOS, you must use the provided Dockerfile to create a compatible development environment.
What happens if my harness returns a non-zero value?
The harness must return 0. Returning other values may interfere with the fuzzer's internal state tracking.
How do I prevent Ruby exceptions from stopping the fuzzing process?
Wrap your target code in a begin-rescue block to catch and suppress standard Ruby exceptions while allowing memory corruption errors to pass to the sanitizer.

How it compares

Unlike standard Ruby testing frameworks that rely on static assertions, Ruzzy actively mutates input and monitors memory states to discover edge-case crashes that manual test suites cannot predict.

Source & trust

⭐ 5.7k starsπŸ“„ CC-BY-SA-4.0πŸ•’ Updated 2026-06-15
πŸ“„ Full skill instructions β€” original source: trailofbits/skills
# Ruzzy

Ruzzy is a coverage-guided fuzzer for Ruby built on libFuzzer. It enables fuzzing both pure Ruby code and Ruby C extensions with sanitizer support for detecting memory corruption and undefined behavior.

## When to Use

Ruzzy is currently the only production-ready coverage-guided fuzzer for Ruby.

**Choose Ruzzy when:**
- Fuzzing Ruby applications or libraries
- Testing Ruby C extensions for memory safety issues
- You need coverage-guided fuzzing for Ruby code
- Working with Ruby gems that have native extensions

## Quick Start

Set up environment:
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"


Test with the included toy example:
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby -e 'require "ruzzy"; Ruzzy.dummy'


This should quickly find a crash demonstrating that Ruzzy is working correctly.

## Installation

### Platform Support

Ruzzy supports Linux x86-64 and AArch64/ARM64. For macOS or Windows, use the [Dockerfile](https://github.com/trailofbits/ruzzy/blob/main/Dockerfile) or [development environment](https://github.com/trailofbits/ruzzy#developing).

### Prerequisites

- Linux x86-64 or AArch64/ARM64
- Recent version of clang (tested back to 14.0.0, latest release recommended)
- Ruby with gem installed

### Installation Command

Install Ruzzy with clang compiler flags:

MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
gem install ruzzy


**Environment variables explained:**
- MAKE: Overrides make to respect subsequent environment variables
- CC, CXX, LDSHARED, LDSHAREDXX: Ensure proper clang binaries are used for latest features

### Troubleshooting Installation

If installation fails, enable debug output:

RUZZY_DEBUG=1 gem install --verbose ruzzy


### Verification

Verify installation by running the toy example (see Quick Start section).

## Writing a Harness

### Fuzzing Pure Ruby Code

Pure Ruby fuzzing requires two scripts due to Ruby interpreter implementation details.

**Tracer script (test_tracer.rb):**

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')


**Harness script (test_harness.rb):**

# frozen_string_literal: true

require 'ruzzy'

def fuzzing_target(input)
# Your code to fuzz here
if input.length == 4
if input[0] == 'F'
if input[1] == 'U'
if input[2] == 'Z'
if input[3] == 'Z'
raise
end
end
end
end
end
end

test_one_input = lambda do |data|
fuzzing_target(data)
return 0
end

Ruzzy.fuzz(test_one_input)


Run with:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby test_tracer.rb


### Fuzzing Ruby C Extensions

C extensions can be fuzzed with a single harness file, no tracer needed.

**Example harness for msgpack (fuzz_msgpack.rb):**

# frozen_string_literal: true

require 'msgpack'
require 'ruzzy'

test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# We're looking for memory corruption, not Ruby exceptions
end
return 0
end

Ruzzy.fuzz(test_one_input)


Run with:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby fuzz_msgpack.rb


### Harness Rules

| Do | Don't |
|----|-------|
| Catch Ruby exceptions if testing C extensions | Let Ruby exceptions crash the fuzzer |
| Return 0 from test_one_input lambda | Return other values |
| Keep harness deterministic | Use randomness or time-based logic |
| Use tracer script for pure Ruby | Skip tracer for pure Ruby code |

> **See Also:** For detailed harness writing techniques, patterns for handling complex inputs,
> and advanced strategies, see the **fuzz-harness-writing** technique skill.

## Compilation

### Installing Gems with Sanitizers

When installing Ruby gems with C extensions for fuzzing, compile with sanitizer flags:

MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
gem install <gem-name>


### Build Flags

| Flag | Purpose |
|------|---------|
| -fsanitize=address,fuzzer-no-link | Enable AddressSanitizer and fuzzer instrumentation |
| -fno-omit-frame-pointer | Improve stack trace quality |
| -fno-common | Better compatibility with sanitizers |
| -fPIC | Position-independent code for shared libraries |
| -g | Include debug symbols |

## Running Campaigns

### Environment Setup

Before running any fuzzing campaign, set ASAN_OPTIONS:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"


**Options explained:**
1. allocator_may_return_null=1: Skip common low-impact allocation failures (DoS)
2. detect_leaks=0: Ruby interpreter leaks data, ignore these for now
3. use_sigaltstack=0: Ruby recommends disabling sigaltstack with ASan

### Basic Run

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb


**Note:** LD_PRELOAD is required for sanitizer injection. Unlike ASAN_OPTIONS, do not export it as it may interfere with other programs.

### With Corpus

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpus


### Passing libFuzzer Options

All libFuzzer options can be passed as arguments:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10


See [libFuzzer options](https://llvm.org/docs/LibFuzzer.html#options) for full reference.

### Reproducing Crashes

Re-run a crash case by passing the crash file:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980


### Interpreting Output

| Output | Meaning |
|--------|---------|
| INFO: Running with entropic power schedule | Fuzzing campaign started |
| ERROR: AddressSanitizer: heap-use-after-free | Memory corruption detected |
| SUMMARY: libFuzzer: fuzz target exited | Ruby exception occurred |
| artifact_prefix='./'; Test unit written to ./crash-* | Crash input saved |
| Base64: ... | Base64 encoding of crash input |

## Sanitizer Integration

### AddressSanitizer (ASan)

Ruzzy includes a pre-compiled AddressSanitizer library:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb


Use ASan for detecting:
- Heap buffer overflows
- Stack buffer overflows
- Use-after-free
- Double-free
- Memory leaks (disabled by default in Ruzzy)

### UndefinedBehaviorSanitizer (UBSan)

Ruzzy also includes UBSan:

LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
ruby harness.rb


Use UBSan for detecting:
- Signed integer overflow
- Null pointer dereferences
- Misaligned memory access
- Division by zero

### Common Sanitizer Issues

| Issue | Solution |
|-------|----------|
| Ruby interpreter leak warnings | Use ASAN_OPTIONS=detect_leaks=0 |
| Sigaltstack conflicts | Use ASAN_OPTIONS=use_sigaltstack=0 |
| Allocation failure spam | Use ASAN_OPTIONS=allocator_may_return_null=1 |
| LD_PRELOAD interferes with tools | Don't export it; set inline with ruby command |

> **See Also:** For detailed sanitizer configuration, common issues, and advanced flags,
> see the **address-sanitizer** and **undefined-behavior-sanitizer** technique skills.

## Real-World Examples

### Example: msgpack-ruby

Fuzzing the msgpack MessagePack parser for memory corruption.

**Install with sanitizers:**

MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
gem install msgpack


**Harness (fuzz_msgpack.rb):**

# frozen_string_literal: true

require 'msgpack'
require 'ruzzy'

test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# We're looking for memory corruption, not Ruby exceptions
end
return 0
end

Ruzzy.fuzz(test_one_input)


**Run:**

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby fuzz_msgpack.rb


### Example: Pure Ruby Target

Fuzzing pure Ruby code with a custom parser.

**Tracer (test_tracer.rb):**

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')


**Harness (test_harness.rb):**

# frozen_string_literal: true

require 'ruzzy'
require_relative 'my_parser'

test_one_input = lambda do |data|
begin
MyParser.parse(data)
rescue StandardError
# Expected exceptions from malformed input
end
return 0
end

Ruzzy.fuzz(test_one_input)


**Run:**

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby test_tracer.rb


## Troubleshooting

| Problem | Cause | Solution |
|---------|-------|----------|
| Installation fails | Wrong clang version or path | Verify clang path, use clang 14.0.0+ |
| cannot open shared object file | LD_PRELOAD not set | Set LD_PRELOAD inline with ruby command |
| Fuzzer immediately exits | Missing corpus directory | Create corpus directory or pass as argument |
| No coverage progress | Pure Ruby needs tracer | Use tracer script for pure Ruby code |
| Leak detection spam | Ruby interpreter leaks | Set ASAN_OPTIONS=detect_leaks=0 |
| Installation debug needed | Compilation errors | Use RUZZY_DEBUG=1 gem install --verbose ruzzy |

## Related Skills

### Technique Skills

| Skill | Use Case |
|-------|----------|
| **fuzz-harness-writing** | Detailed guidance on writing effective harnesses |
| **address-sanitizer** | Memory error detection during fuzzing |
| **undefined-behavior-sanitizer** | Detecting undefined behavior in C extensions |
| **libfuzzer** | Understanding libFuzzer options (Ruzzy is built on libFuzzer) |

### Related Fuzzers

| Skill | When to Consider |
|-------|------------------|
| **libfuzzer** | When fuzzing Ruby C extension code directly in C/C++ |
| **aflpp** | Alternative approach for fuzzing Ruby by instrumenting Ruby interpreter |

## Resources

### Key External Resources

**[Introducing Ruzzy, a coverage-guided Ruby fuzzer](https://blog.trailofbits.com/2024/03/29/introducing-ruzzy-a-coverage-guided-ruby-fuzzer/)**
Official Trail of Bits blog post announcing Ruzzy, covering motivation, architecture, and initial results.

**[Ruzzy GitHub Repository](https://github.com/trailofbits/ruzzy)**
Source code, additional examples, and development instructions.

**[libFuzzer Documentation](https://llvm.org/docs/LibFuzzer.html)**
Since Ruzzy is built on libFuzzer, understanding libFuzzer options and behavior is valuable.

**[Fuzzing Ruby C extensions](https://github.com/trailofbits/ruzzy#fuzzing-ruby-c-extensions)**
Detailed guide on fuzzing C extensions with compilation flags and examples.

**[Fuzzing pure Ruby code](https://github.com/trailofbits/ruzzy#fuzzing-pure-ruby-code)**
Detailed guide on the tracer pattern required for pure Ruby fuzzing.

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/ruzzy/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/trailofbits/skills/ruzzy/SKILL.md
  • Cursor: ~/.cursor/skills/trailofbits/skills/ruzzy/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/trailofbits/skills/ruzzy/SKILL.md

πŸš€ Install with CLI:
npx skills add trailofbits/skills

Read the Master Guide: Mastering Agent Skills β†’

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid security & vulnerability analysis issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Security & Vulnerability Analysis and is published by Trail of Bits, maintained in trailofbits/skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.