How the OpenHuman Module Registry Validates and Loads TinyBus CDylib Modules Using SHA-256 Verification

The OpenHuman module registry uses a compiled-in whitelist of ModuleRecord entries combined with runtime SHA-256 digest verification to ensure only cryptographically attested TinyBus native modules (cdylib) are downloaded, extracted, and dynamically loaded.

The tinyhumansai/openhuman repository implements a secure native module system where every loadable TinyBus dynamic library is catalogued in a static registry. This architecture prevents runtime injection of unauthorized code by enforcing cryptographic verification at multiple stages before dlopen ever executes.

The Compiled-In Registry Architecture

OpenHuman maintains its security boundary through a compiled-in registry defined in src/openhuman/modules/registry.rs. Unlike dynamic module marketplaces that accept runtime registrations, this static table prevents attackers from introducing arbitrary loadable modules after compilation.

Each entry is a ModuleRecord structure defined in src/openhuman/modules/types.rs. These records encapsulate the module's identity, versioning, and platform-specific assets. The registry serves as the single source of truth for:

  • Module IDs and bus names (e.g., tinydocs, tinywallet)
  • Object paths mapped to bus names (converting . to /)
  • Release URLs pointing to GitHub release tags
  • Platform assets containing expected SHA-256 digests
  • Load policies determining initialization timing

The registry initialization includes comments (lines 3-10 in registry.rs) explicitly documenting why the whitelist is compiled rather than configurable: to eliminate attack vectors where malicious actors might append unauthorized entries at runtime.

SHA-256 Verification Flow

When a session requests a native capability, the TinyBus loader executes a four-stage validation pipeline. The OpenHuman registry provides the ground-truth digests that TinyBus uses to verify downloaded artifacts.

Fetching the Release Checksum

The loader first queries the release_url specified in the ModuleRecord (e.g., https://github.com/tinyhumansai/tinydocs/releases/tag/v0.1.14). It downloads the checksum.toml file associated with the release, which contains metadata for all distributed archives.

Platform Asset Selection

Not every release artifact runs on every host. The candidates_for function in src/openhuman/modules/platform.rs generates a prioritized list of host keys based on the current operating system, architecture, and glibc version (e.g., linux-x86_64).

The loader selects the PlatformAsset from the ModuleRecord whose host key matches the current environment. This selection determines which archive name and SHA-256 digest will be used for verification.

Cryptographic Digest Verification

Before extraction begins, TinyBus computes the SHA-256 hash of the downloaded archive in its entirety. It compares this computed digest against the lower-case 64-character hexadecimal string stored in the sha256 field of the selected PlatformAsset.

If the digests differ by even a single bit, the loading process aborts immediately. This verification occurs before any dlopen call, ensuring that corrupted or tampered binaries never execute in-process.

Runtime Loading and dlopen

Upon successful hash validation, the archive extracts to a temporary location. The loader then performs dlopen on the resulting .so, .dylib, or .dll file. Following successful load, OpenHuman validates that the module's bus name correctly maps to its advertised object path through the conversion logic tested in every_object_path_matches_its_bus_name (lines 87-95 in registry.rs).

Load Policies and Module Lifecycle

The registry distinguishes between two initialization strategies via the LoadPolicy enum:

  • LoadPolicy::Eager — Modules like tinymemory load at startup because their absence would alter the core RPC surface available to clients.
  • LoadPolicy::Lazy — Modules such as tinydocs, tinywallet, and tinyjuice remain dormant until a session explicitly requests their capability, conserving memory and reducing attack surface during idle periods.

This policy is encoded in the ModuleRecord and enforced by the session manager when initializing the TinyBus runtime.

Registry Validation and Security Invariants

The registry.rs file contains comprehensive unit tests (lines 74-124) that enforce data integrity at compile time. These tests verify:

  • Uniqueness constraints — No duplicate module IDs or bus names exist.
  • Path consistency — Every object path correctly derives from its bus name.
  • Digest format — All SHA-256 strings are exactly 64 lower-case hexadecimal characters.
  • Archive naming — Asset filenames encode their host key and semantic version.
  • URL integrity — Release URLs point to GitHub tags matching the recorded version string.

These invariants ensure that the compiled-in whitelist contains only well-formed, internally consistent records before the binary ships.

Implementation Example

The following Rust code demonstrates how consumer code interacts with the registry and verification pipeline:

// 1. Locate a module record by its ID (e.g., "tinydocs")
use openhuman::modules::registry::{find, ALL};

let record = find("tinydocs")
    .expect("module ID not known");

// 2. Choose the correct asset for the current platform
use openhuman::modules::platform::candidates_for;
let host_keys = candidates_for("linux", "x86_64", Some((2, 39)));
let asset = record.asset_for(&host_keys[0])
    .expect("no asset for this host");

// 3. Verify the SHA-256 digest (TinyBus does this internally)
//    Here we show the expected digest for reference:
println!("Expected SHA-256: {}", asset.sha256);

// 4. Load the module (TinyBus provides the loader)
use openhuman::modules::loader::load_module;
let module = load_module(record).expect("failed to load module");

// 5. Use the module via TinyBus (example: call a TinyBus method)
let result = module.call("SomeMethod", args);

Note that while OpenHuman supplies the static ModuleRecord and host-key selection logic in src/openhuman/modules/, the actual download, SHA-256 verification, and dlopen operations are performed by the TinyBus runtime (tinybus::load::load_module).

Summary

  • The compiled-in registry at src/openhuman/modules/registry.rs acts as a whitelist preventing runtime injection of unauthorized modules.
  • Each ModuleRecord contains platform-specific assets with expected SHA-256 digests stored in lower-case hexadecimal format.
  • The verification flow fetches checksum.toml, matches host keys via candidates_for, compares cryptographic digests, and only then proceeds to dlopen.
  • Load policies (Lazy vs Eager) control whether modules initialize at startup or on-demand.
  • Unit tests enforce uniqueness, path consistency, and digest format invariants before compilation.

Frequently Asked Questions

How does OpenHuman prevent loading of modified or malicious TinyBus modules?

OpenHuman prevents tampering through SHA-256 attestation stored in PlatformAsset records. Before dlopen executes, TinyBus downloads the module archive and computes its SHA-256 hash. The loader aborts if the computed digest does not match the 64-character hexadecimal string defined in src/openhuman/modules/registry.rs. This ensures only cryptographically identical binaries to those published in the GitHub release execute.

What happens if a requested module is not in the compiled-in registry?

If find() in src/openhuman/modules/registry.rs returns None for a requested module ID, the loading process fails immediately. Because the registry is compiled into the binary and cannot be modified at runtime, there is no mechanism to load "unlisted" modules, effectively preventing dynamic code injection attacks.

How does the registry handle different operating systems and architectures?

The candidates_for function in src/openhuman/modules/platform.rs generates host keys representing the current OS/architecture tuple (e.g., linux-x86_64). Each ModuleRecord contains multiple PlatformAsset entries for different host keys. The loader selects the asset matching the current environment, ensuring the correct .so, .dylib, or .dll variant loads with its corresponding SHA-256 digest.

What is the difference between Lazy and Eager load policies?

Eager modules (such as tinymemory) initialize during OpenHuman startup because their absence would change the available RPC methods. Lazy modules (including tinydocs and tinywallet) defer download and dlopen until a session explicitly requests their capability, reducing resource consumption and attack surface during periods when those features remain unused.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →