RepoPilotOpen in app →

david942j/one_gadget

The best tool for finding one gadget RCE in libc.so.6

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3w ago
  • 7 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Concentrated ownership — top contributor handles 50% of recent commits
  • No test directory detected

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/david942j/one_gadget)](https://repopilot.app/r/david942j/one_gadget)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/david942j/one_gadget on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: david942j/one_gadget

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/david942j/one_gadget shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 3w ago
  • 7 active contributors
  • MIT licensed
  • CI configured
  • ⚠ Concentrated ownership — top contributor handles 50% of recent commits
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live david942j/one_gadget repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/david942j/one_gadget.

What it runs against: a local clone of david942j/one_gadget — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in david942j/one_gadget | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 49 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>david942j/one_gadget</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of david942j/one_gadget. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/david942j/one_gadget.git
#   cd one_gadget
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of david942j/one_gadget and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "david942j/one_gadget(\\.git)?\\b" \\
  && ok "origin remote is david942j/one_gadget" \\
  || miss "origin remote is not david942j/one_gadget (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "lib/one_gadget.rb" \\
  && ok "lib/one_gadget.rb" \\
  || miss "missing critical file: lib/one_gadget.rb"
test -f "bin/one_gadget" \\
  && ok "bin/one_gadget" \\
  || miss "missing critical file: bin/one_gadget"
test -f "lib/one_gadget/abi.rb" \\
  && ok "lib/one_gadget/abi.rb" \\
  || miss "missing critical file: lib/one_gadget/abi.rb"
test -f "lib/one_gadget/builds" \\
  && ok "lib/one_gadget/builds" \\
  || miss "missing critical file: lib/one_gadget/builds"
test -f "Gemfile" \\
  && ok "Gemfile" \\
  || miss "missing critical file: Gemfile"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 49 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~19d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/david942j/one_gadget"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

OneGadget is a Ruby-based symbolic execution tool that automatically finds one-gadget RCE (remote code execution) chains in libc.so.6 across i386, x86-64, and aarch64 architectures. It eliminates the need to manually search through objdump/IDA output to locate gadgets that call execve('/bin/sh', NULL, NULL) by analyzing constraints and proving which gadget chains will succeed. Modular architecture: lib/one_gadget.rb is the entry point, lib/one_gadget/abi.rb handles architecture-specific logic (i386/x64/aarch64), lib/one_gadget/builds/ contains a pre-computed database of 100+ libc build variants with known gadget offsets and constraints, and bin/one_gadget provides the CLI wrapper. The tool loads the appropriate build file, applies symbolic execution to validate constraints, and ranks results by success probability.

👥Who it's for

CTF (Capture The Flag) pwn challenge competitors and exploit developers who need to quickly identify working gadgets in target libc binaries without manual reverse engineering.

🌱Maturity & risk

Production-ready and actively maintained. The project has been around since 2017 (visible from blog post reference), has comprehensive CI/CD via GitHub Actions (.github/workflows/ruby.yml), uses quality tools (Qlty, RuboCop, RSpec), and maintains a curated database of 100+ pre-analyzed libc build variants under lib/one_gadget/builds/. The codebase is 2.8M lines of Ruby with strong test coverage signals.

Low risk for a specialized tool with narrow scope. Single maintainer (david942j) is the primary concern for long-term support, but the gem has been stable since 2017 with predictable updates tied to glibc releases. Dependency surface is minimal (pure Ruby with no external binary deps), though the tool's accuracy depends on maintaining the manually-curated builds database as glibc evolves.

Active areas of work

Active maintenance with CI passing (ruby.yml workflow). Recent activity focuses on keeping the builds database current as new glibc versions are released. Dependabot is configured (.github/dependabot.yml) to track Ruby dependency updates automatically.

🚀Get running

gem install one_gadget
one_gadget /path/to/libc.so.6

Or clone and develop locally:

git clone https://github.com/david942j/one_gadget.git
cd one_gadget
bundle install
bundle exec ./bin/one_gadget /path/to/libc

Daily commands:

bundle exec ./bin/one_gadget /path/to/libc.so.6
bundle exec rake  # Run full test suite
bundle exec rspec # Run RSpec tests

Dev workflow: edit files in lib/, rebuild examples via examples/*.png generation (documented in README.tpl.md).

🗺️Map of the codebase

  • lib/one_gadget.rb — Main entry point and public API for the gem; all external consumers interact through this file
  • bin/one_gadget — CLI interface that demonstrates how to use the library and is the primary user-facing tool
  • lib/one_gadget/abi.rb — Core ABI (Application Binary Interface) abstraction that handles architecture-specific gadget constraints
  • lib/one_gadget/builds — Precomputed gadget database for hundreds of libc builds; the foundation of gadget lookups
  • Gemfile — Dependency management; critical for understanding runtime requirements and version constraints
  • README.md — Comprehensive documentation on usage, features, and examples that every contributor should understand
  • .rspec — Test configuration that defines the testing framework and conventions used throughout the project

🧩Components & responsibilities

  • CLI (bin/one_gadget) (Ruby OptionParser, string formatting) — Parse command-line arguments, invoke core API, format and display results
    • Failure mode: Crashes if invalid arguments; user sees error message instead of gadget results
  • Core API (lib/one_gadget.rb) (Ruby module system, dynamic requires) — Main search orchestration; load build database, filter gadgets, apply constraints
    • Failure mode: Returns empty result set if no matching gadgets found; returns nil if libc build not in database
  • ABI Module (lib/one_gadget/abi.rb) (Ruby classes, constraint objects) — Define architecture-specific calling conventions and safety constraints
    • Failure mode: Incorrectly filters gadgets if constraints are misconfigured; could allow unsafe gadgets
  • Build Database (lib/one_gadget/builds/) (Ruby source files dynamically loaded at runtime) — Precomputed gadget offsets and metadata for each libc variant
    • Failure mode: If build file is corrupted or missing, gadgets cannot be retrieved for that libc version

🔀Data flow

  • User shell commandCLI (bin/one_gadget) — User invokes tool with libc path, architecture, and optional filters
  • CLICore API (lib/one_gadget.rb) — Parsed arguments passed to main search function
  • Core APIBuild Database (lib/one_gadget/builds/) — Dynamically load build-specific gadget definitions matching the target libc
  • Build DatabaseABI Module (lib/one_gadget/abi.rb) — Gadget offsets paired with architecture constraints for filtering
  • ABI ModuleCore API — Returns filtered gadgets that satisfy architecture constraints
  • Core APICLI — Gadget results with offsets, conditions, and metadata
  • CLIUser terminal — Formatted output: one-gadget RCE offsets, code snippets, and usage notes

🛠️How to make changes

Add support for a new libc build variant

  1. Generate gadget offsets for the new libc build using the internal analysis tools (lib/one_gadget/builds/)
  2. Create a new file named libc-<VERSION>-<BUILD_ID>.rb following the existing pattern in lib/one_gadget/builds/ (lib/one_gadget/builds/libc-2.19-01e14462fc6097604edd54a2ee63664c65b2c12b.rb)
  3. Define gadget offsets and constraints using the ABI system to encode architecture-specific rules (lib/one_gadget/abi.rb)
  4. Test the new build by running one_gadget against it to verify gadget resolution (.rspec)

Add a new architecture/ABI constraint

  1. Define the new architecture's calling convention and register constraints (lib/one_gadget/abi.rb)
  2. Update the main library to recognize and route the new architecture (lib/one_gadget.rb)
  3. Add example screenshot demonstrating the new architecture in action (examples/aarch64.png)

Extend CLI with new search filters or output formats

  1. Add new command-line argument parsers in the CLI entry point (bin/one_gadget)
  2. Implement the new filter/format logic in the core API (lib/one_gadget.rb)
  3. Update README with new usage examples and screenshots (README.md)

🔧Why these technologies

  • Ruby — Simple scripting language ideal for binary analysis and quick prototyping; Gem distribution makes installation trivial
  • Precomputed Build Database — Eliminates runtime binary analysis overhead; trades disk space for instant gadget lookups with 100% accuracy
  • ABI-based Constraint System — Encodes architecture-specific calling conventions and register safety rules in a reusable abstraction

⚖️Trade-offs already made

  • Precomputed gadgets rather than dynamic analysis

    • Why: Speed and reliability are critical for CTF/security workflows
    • Consequence: Database must be maintained for new libc versions; size grows linearly with supported builds
  • Single gemfile with 600+ build definition files

    • Why: Keeps all data in one package; no external network dependency
    • Consequence: Large gem size (~5MB+); distribution/download overhead for end users
  • Ruby over compiled languages (C/Rust)

    • Why: Rapid development and ease of distribution via RubyGems
    • Consequence: Slower startup time than compiled tools; not suitable for high-throughput server scenarios

🚫Non-goals (don't propose these)

  • Perform dynamic binary analysis on arbitrary ELF files
  • Support libc versions older than 2.19
  • Provide real-time detection of zero-day gadgets
  • Run on non-Linux systems (target libc is Linux-specific)
  • Handle non-GNU libc implementations (musl, glibc variants)

⚠️Anti-patterns to avoid

  • Dynamic require for build database lookup (Medium)lib/one_gadget.rb (inferred from architecture): Loading 600+ Ruby files dynamically at runtime could cause slow gadget lookups if not properly memoized; vulnerable to injection if build ID is user-controlled without sanitization
  • Hardcoded constraint values across ABI definitionslib/one_gadget/abi.rb: Constraint rules (register values, memory offsets) may be duplicated across architecture definitions instead of centralized in

🪤Traps & gotchas

Build ID matching: The tool first searches by BuildID (libc's embedded SHA1 hash) before falling back to file path with -f flag; if your libc doesn't match a pre-computed build variant, you must add it to lib/one_gadget/builds/. Constraint evaluation: Gadget constraints are symbolic lambdas evaluated against register state; setting them too strict filters valid gadgets, too loose returns false positives. Arch detection: The tool infers architecture from libc ELF header; mismatched architecture will silently return no gadgets. Ruby version: Requires Ruby 2.1.0+ (check via ruby --version); some constraint syntax may differ on older 2.1 vs modern Ruby.

🏗️Architecture

💡Concepts to learn

  • Symbolic Execution — OneGadget's core technique: instead of testing gadgets at runtime, it symbolically evaluates register/stack constraints to prove which gadgets will succeed, enabling offline gadget discovery
  • One-Gadget RCE — The specific exploit primitive this tool targets: a single libc address that, when jumped to with controlled registers/stack, will execute a shell without needing a full ROP chain
  • Build ID (ELF GNU_BUILD_ID) — OneGadget matches libc binaries by their ELF Build ID hash rather than version strings, enabling precise gadget lookups even for custom-built or patched libc variants
  • ROP (Return-Oriented Programming) — The attack technique one-gadgets simplify: instead of chaining many small ROP gadgets, a single one-gadget can spawn a shell if constraints are met
  • Constraint Solving — Each gadget in the builds database has constraints (e.g., 'rax must be null, rdx must be writable') that OneGadget evaluates to rank gadgets by success probability
  • ABI (Application Binary Interface) — OneGadget must understand calling conventions and register usage for each architecture (i386/x64/aarch64) to correctly interpret constraints and gadget behavior
  • ELF Binary Format — OneGadget parses ELF headers and sections to extract Build IDs, find gadget offsets, and determine target architecture when analyzing libc binaries
  • shellphish/patcherex — Complementary CTF tool for binary patching; often used alongside one_gadget when exploits need to modify libc behavior
  • Gallopsled/pwntools — Industry-standard CTF exploit framework in Python; many exploit scripts use one_gadget output as input to pwntools' ROP/shellcode chains
  • angr/angr — General-purpose binary analysis engine with symbolic execution; one_gadget uses similar techniques but specialized for libc gadget-finding
  • ROPgadget/ROPgadget — Classic ROP gadget finder; one_gadget is more specialized (libc-only, one-gadget specific) but shares similar constraint-solving philosophy
  • torvalds/linux — Upstream source for glibc (in glibc/ subdir); critical for understanding why gadgets fail/succeed based on kernel interfaces

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add architecture-specific integration tests for ABI detection

The repo has lib/one_gadget/abi.rb and extensive libc build files for multiple architectures (x86_64, i386, aarch64 based on examples). However, there's no evidence of comprehensive tests validating ABI detection across different architectures. This would catch regressions when adding new libc builds or modifying ABI detection logic.

  • [ ] Create spec/one_gadget/abi_spec.rb with tests for ABI detection on x86_64, i386, and aarch64
  • [ ] Add integration tests in spec that verify correct gadget selection for each architecture
  • [ ] Reference the example files in examples/ (aarch64.png, i386.png, x86_64.png) to understand expected behavior
  • [ ] Test edge cases like mismatched build IDs and unsupported architectures

Implement build database consistency validator

The lib/one_gadget/builds/ directory contains 100+ libc build files with a pattern (e.g., libc-2.19-HASH.rb). There's no visible tool to validate that all these build files are syntactically correct, don't have duplicate gadgets, or follow consistent formatting. A Rake task would help maintain data quality.

  • [ ] Create lib/one_gadget/builds/validator.rb to parse and validate all build files in lib/one_gadget/builds/
  • [ ] Add a Rakefile task (rake validate_builds) that checks: file naming conventions, Ruby syntax, duplicate gadget offsets per build, required metadata fields
  • [ ] Add CI integration in .github/workflows/ruby.yml to run this validation on every PR
  • [ ] Document the build file format in README.md with schema requirements

Add support for libc build lookup by version range and add test coverage

The bin/one_gadget CLI has examples for --build-id lookup (examples/from_build_id.png), but there's no visible way to query gadgets for a specific libc version range (e.g., 'find gadgets compatible with glibc 2.19-2.31'). Adding this feature with tests would improve usability for environments with multiple glibc versions.

  • [ ] Add method to lib/one_gadget.rb or new lib/one_gadget/search.rb to query builds by version range
  • [ ] Update bin/one_gadget CLI to accept --glibc-version flag (e.g., --glibc-version 2.19+)
  • [ ] Add unit tests in spec/one_gadget/search_spec.rb covering version matching and precedence logic
  • [ ] Update README.md with examples of version-based queries and test with the existing build files in lib/one_gadget/builds/

🌿Good first issues

  • Add test coverage for lib/one_gadget/abi.rb: create spec/one_gadget/abi_spec.rb with unit tests for instruction parsing on i386 and aarch64 architectures (currently only x86-64 seems heavily tested)
  • Document the constraint lambda DSL: write a guide in docs/ or README showing how constraints work (e.g., why rax == 0 succeeds vs fails) with 3-4 real examples from lib/one_gadget/builds/ annotated
  • Add support for libc 2.31+ builds: identify 5-10 new glibc version/build combos from modern Ubuntu/Debian releases, generate their build files via the tool, and add them to lib/one_gadget/builds/ (good way to learn the database format)

Top contributors

Click to expand

📝Recent commits

Click to expand
  • e93d61f — Bump yard from 0.9.42 to 0.9.43 (#299) (dependabot[bot])
  • 293ccb1 — Bump rake from 13.4.1 to 13.4.2 (#298) (dependabot[bot])
  • 9c7a34b — Bump yard from 0.9.41 to 0.9.42 (#297) (dependabot[bot])
  • cade450 — Bump rake from 13.3.1 to 13.4.1 (#295) (dependabot[bot])
  • 2c66304 — Bump yard from 0.9.40 to 0.9.41 (#296) (dependabot[bot])
  • 1cb6d01 — Bump yard from 0.9.38 to 0.9.40 (#294) (dependabot[bot])
  • 7610672 — Drop Ruby 3.2 support (#293) (david942j)
  • 1be977a — Bump rubocop from 1.81.7 to 1.85.1 (#286) (dependabot[bot])
  • 479ea6e — Bump mcp from 0.8.0 to 0.9.2 (#292) (dependabot[bot])
  • 63ea516 — Bump addressable from 2.8.9 to 2.9.0 (#290) (dependabot[bot])

🔒Security observations

The one_gadget codebase is a specialized security research tool with moderate security posture. Primary concerns are: (1) the dynamic loading of hundreds of pre-built gadget definitions without apparent integrity verification, (2) dependency management visibility, and (3) lack of explicit security documentation for users analyzing untrusted binaries. The tool itself does not expose typical web application vulnerabilities (SQLi, XSS, RCE via user input), but as a binary analysis tool, it should implement additional safeguards for code integrity and safe handling of potentially malicious binaries. Recommended actions: implement cryptographic verification of gadget definitions, ensure secure dependency management with regular audits, and add comprehensive security documentation.

  • Medium · Large Number of Pre-built Libc Definitions — lib/one_gadget/builds/. The codebase contains hundreds of pre-built libc definitions (lib/one_gadget/builds/) that are auto-loaded. While this is by design for the tool's functionality, it creates a large attack surface if any of these files are compromised or contain malicious gadget definitions. Fix: Implement cryptographic integrity verification (checksums/signatures) for all pre-built libc definition files. Consider implementing a manifest file that validates all gadget definitions on load.
  • Medium · Dynamic Code Loading from Gem — lib/one_gadget/. The one_gadget tool dynamically loads and executes code from pre-built libc definition files. If the gem is installed from an untrusted source or if a dependency is compromised, arbitrary code could be executed during gem installation or runtime. Fix: Ensure the gem is obtained only from official sources (rubygems.org). Implement code signing for releases. Use bundle audit to regularly check for known vulnerabilities in dependencies.
  • Low · Missing Input Validation Documentation — README.md, lib/one_gadget.rb. While no explicit injection vulnerabilities are visible in the file structure, a security-focused tool like this should have clear documentation on input validation and safe usage patterns when analyzing untrusted binaries. Fix: Add security documentation section to README covering: input validation practices, safe usage with untrusted binaries, and potential denial-of-service vectors from extremely large binaries.
  • Low · No Dependency Pinning Visible — Gemfile, Gemfile.lock. Gemfile and Gemfile.lock content was not provided in the analysis, making it impossible to verify if all dependencies are pinned to specific versions. Unpinned dependencies can lead to unexpected breaking changes or security updates being missed. Fix: Ensure all dependencies in Gemfile.lock are pinned to exact versions. Use bundle audit in CI/CD pipeline to detect vulnerable dependencies. Regularly update dependencies and monitor security advisories.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · david942j/one_gadget — RepoPilot