Files
clawhdf5/research/06-security-hardening.md
T
ClawHDF5 PlannerandClaude Sonnet 4.6 14db35aa74 research: ClawHDF5 deep-dive — architecture, performance, robustness, security
Seven research briefs covering the full mission scope:
01 — Architecture overview (crate map, format coverage, agent modules)
02 — Roadmap status and strategic gaps (distribution, MPI-IO, encryption)
03 — HDF5 ecosystem and cutting-edge developments (HDF5 2.0, Blosc2, ANN trends)
04 — Performance optimizations (10 opportunities, prioritized)
05 — Robustness enhancements (fuzzing gaps, bounds audit, WAL, KG cycle guard)
06 — Security hardening (encryption, signing, embedding poisoning, JNI safety)
07 — Synthesis and 15 actionable next steps with INT-NN task markers

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-08-12 11:25:53 +00:00

13 KiB
Raw Blame History

Security Audit & Hardening Recommendations

Research brief — generated 2026-08-12


1. Threat Model

ClawHDF5 operates in two distinct threat environments:

Environment A — Untrusted HDF5 files: A user opens an HDF5 file from an untrusted source (downloaded file, network stream, user upload). The format parser must not crash, OOM, or execute arbitrary code.

Environment B — Agent memory under adversarial input: An AI agent writes memories sourced from external tool output, web content, or multi-agent messages. An adversary may attempt to poison the memory store by injecting crafted content.

Out of scope (by design): Network security (ClawHDF5 is a file-based library with no built-in networking). Authentication and access control at the OS level.


2. Current Security Posture

2.1 What's Already Done (Strong)

Control Implementation Coverage
Decompression output bound MAX_DECOMPRESS_SIZE in filters.rs Deflate, LZ4, Zstd, Pcodec
Allocation guards before alloc Length-prefix caps before Vec::with_capacity calls WAL (MAX_WAL_FIELD_LEN = 64 MiB), VDS mapping parser, H5S decoder
Arithmetic overflow guards ensure_len helper; checked_add / checked_mul in critical paths chunked_read.rs, btree_v1.rs, local_heap.rs, scale-offset, N-Bit
Recursion depth guard Depth counter on cyclic B-tree traversal; N-Bit type tree cap btree_v1.rs, filters.rs
WAL entry integrity CRC32 trailer per entry (WAL_VERSION 2) — bit-flip stops replay cleanly clawhdf5-agent::wal
Content hashing FNV-1a for memory chunks (anomaly detection); SHA-256 for provenance attributes provenance.rs
Injection pattern detection 15 patterns in anomaly.rs Prompt injection, role impersonation, etc.
Write rate limiting anomaly.rs rate limiter Flood attacks on memory store
Source isolation Per-MemorySource sub-stores User vs System vs Tool source separation
Android JNI safety Bounds-check on embedding_len; null pointer rejection clawhdf5-android JNI functions
PyO3 safety pyo3/numpy 0.29 (clears two RUSTSEC advisories) Python bindings
Fuzz coverage fuzz_filter_pipeline, fuzz_dataset_read Filter pipeline; dataset read paths

2.2 Documented Limitations

The CHANGELOG explicitly documents:

"The integrity hashes in clawhdf5-agent::provenance (FNV-1a) and clawhdf5-format::provenance (SHA-256) are unkeyed and detect only accidental corruption, not tampering — doc-only change, no behavior change."

This is an important honesty note: the current provenance system is not a tamper-detection mechanism.


3. Security Gaps & Recommendations

3.1 Missing: Encryption at Rest (HIGH PRIORITY)

Gap: There is no encryption for the HDF5 file or WAL. A .brain file or agent_memory.h5 containing personal data, credentials mentioned in conversation, or proprietary knowledge is stored in plaintext.

Attack scenario: An attacker with filesystem access to the .h5 file (e.g., via a directory traversal vulnerability in an app using ClawHDF5, or physical access to a laptop) can read all agent memories.

Recommendation:

Implement an encryption feature using aes-gcm (from the aes-gcm crate — pure Rust, audited):

// Proposed API addition to MemoryConfig:
pub struct MemoryConfig {
    // ... existing fields ...
    pub encryption_key: Option<[u8; 32]>,  // AES-256-GCM key
}

Implementation approach:

  1. Store a random 96-bit nonce per HDF5 chunk alongside the chunk data.
  2. Encrypt each chunk's decompressed data with AES-256-GCM before writing; decrypt on read.
  3. Encrypt WAL entries with the same key.
  4. Store a key-derivation salt in the file header; derive the working key from a user passphrase via Argon2id.
  5. The HDF5 file is still structurally valid (h5py can open it and see dataset shapes) but all data values are ciphertext — this is a deliberate tradeoff (vs encrypting the entire file as a blob).

Alternative: Encrypt the entire .h5 file as a blob using AES-256-CTR with a random IV stored in a plaintext header. Simpler but loses partial-decryption ability.

Effort estimate: 23 weeks. The aes-gcm and argon2 crates are well-audited and integrate cleanly into Rust.


3.2 Missing: Tamper Detection / Signing (HIGH PRIORITY for .brain files)

Gap: The SHA-256 provenance attributes detect accidental corruption but not intentional tampering. An adversary who can write to the .h5 file can update both the data and the SHA-256 hash.

Attack scenario: A compromised .brain file is distributed from ClawBrainHub. A user downloads it, trusting the provenance hashes, but the hashes have been re-computed over poisoned data.

Recommendation:

  1. Ed25519 signatures: Add an [package] signing_key field to MemoryConfig. When signing is enabled, compute an Ed25519 signature over the dataset contents + SHA-256 provenance hash and store it as an HDF5 attribute. Verify on open.
  2. ClawBrainHub trust chain: The registry should sign .brain files with a registry key. ClawHDF5 should ship a clawhdf5-cli verify command that checks the registry signature.

Crates: ed25519-dalek (pure Rust, widely audited).

Effort estimate: 12 weeks for basic file signing. ClawBrainHub registry integration is a separate effort.


3.3 Incomplete: Embedding-Space Poisoning Detection (MEDIUM PRIORITY)

Gap: The 15 injection patterns in anomaly.rs detect text-level injection attempts (e.g., "Ignore previous instructions"). They do not detect embedding-space poisoning — adversarially crafted embeddings that are semantically close to arbitrary queries in vector space but contain malicious text.

Attack scenario (from MemoryGraft paper): A tool output contains text that, when embedded, produces a vector close to "user preferences" in the embedding space. Future queries for "user preferences" retrieve the poisoned memory instead of genuine ones.

Recommendation:

  1. Embedding anomaly detection: Compute the distribution of embeddings in the store (mean + covariance). Flag new embeddings whose Mahalanobis distance from the distribution centroid exceeds a threshold. This is a statistical outlier detector.
  2. Cluster consistency check: After every write batch, verify that the new embedding does not shift the cluster assignment of nearby memories by more than a configurable fraction.
  3. Source-aware embedding validation: Embeddings from untrusted sources (e.g., MemorySource::Tool) should be quarantined and require explicit promotion to the main store.

Effort estimate: 12 weeks for Mahalanobis detection; 23 weeks for cluster consistency.


3.4 Incomplete: Timestamp Integrity (MEDIUM PRIORITY)

Gap: Memory timestamps are stored in the HDF5 file as plain f64 values. The WAL CRC32 detects accidental bit-flips but not intentional timestamp manipulation by an adversary who writes to the HDF5 file.

Attack scenario: An adversary modifies timestamps in the HDF5 file to make recent poisoned memories appear old (and thus trusted by the temporal re-ranking component) or to make old poisoned memories appear recent.

Recommendation:

  1. Signed timestamps: When file signing is enabled (see 3.2), include timestamps in the signed data.
  2. Monotonic timestamp enforcement: In the write path, reject any attempt to write a timestamp older than the last written timestamp in the same source channel. The WAL's append-only nature already provides this for WAL entries; extend it to the HDF5 dataset.

3.5 JNI Thread Safety (MEDIUM PRIORITY)

Gap: The Android JNI functions operate on a raw *mut HDF5Memory handle with no synchronization. The handle is cast from a jlong and used as &mut HDF5Memory.

Attack scenario: Two Java threads call JNI functions on the same handle simultaneously → data race → undefined behavior in unsafe Rust.

Recommendation:

Wrap the HDF5Memory handle in a Mutex<HDF5Memory> and store the Mutex in a Box (as is standard for JNI handle storage):

// Current:
let memory = unsafe { &mut *(handle as *mut HDF5Memory) };

// Recommended:
let locked = unsafe { &*(handle as *const Mutex<HDF5Memory>) };
let mut memory = locked.lock().unwrap();

Effort estimate: 12 days. Low risk, high impact for multi-threaded Android use.


3.6 Media Reference Sandboxing (MEDIUM PRIORITY)

Gap: MediaRef::Path stores filesystem paths from arbitrary sources (including adversarial memory content). If the agent resolves these paths, a crafted ../../../etc/passwd path could expose sensitive files.

Recommendation:

  1. Allowlist-based path validation: The agent should only resolve MediaRef::Path entries that are within a configured media_sandbox_dir.
  2. Canonicalization before resolution: Always call std::fs::canonicalize before resolving a path, then check it is within the sandbox.
  3. URL scheme allowlist: MediaRef::Url should only allow https:// by default. Reject file://, data:, javascript:, etc.

3.7 SZIP FFI Safety (LOW PRIORITY)

Gap: The szip feature introduces libaec C FFI. Incorrect FFI arguments (wrong chunk_size, mismatched bits_per_sample) could cause the C library to write past the allocated output buffer.

Recommendation:

  1. The current implementation validates cd.len() >= 5 and checks bits_per_sample > 0 && <= 32. Add a check that chunk_size is non-zero and does not exceed a maximum (e.g., 512 MiB).
  2. Consider wrapping the aec_buffer_decode call in std::panic::catch_unwind (if the C library signals errors via signals, not return codes — verify with libaec docs).
  3. Add a fuzz target (fuzz_szip_decompress) when the szip feature is enabled.

3.8 Denial of Service: Adversarial HDF5 Files (LOW PRIORITY — partially mitigated)

Current mitigations: MAX_DECOMPRESS_SIZE, allocation guards, recursion depth caps, H5S_MAX_RANK cap. These collectively address the most dangerous DoS vectors.

Remaining gaps:

  1. Large group with many dense links: A group with millions of links in the v2 B-tree will take O(N) memory to iterate. Add a cap (MAX_LINKS_PER_GROUP) that returns an error rather than allocating unboundedly.
  2. Very long string attributes: The local_heap.rs fixes guard overflow arithmetic but there is no explicit cap on total string heap size. Add MAX_STRING_HEAP_BYTES.
  3. Deeply nested compound types: The N-Bit type tree recursion is now capped (CHANGELOG), but compound types can also be nested arbitrarily. Verify compound type recursion depth is capped.

4. Dependency Security

4.1 RUSTSEC Advisories

The pyo3/numpy bump (0.28 → 0.29) cleared two RUSTSEC advisories. Recommended:

  • Add cargo-audit to CI: cargo audit --deny warnings after every dependency update.
  • Pin a cargo-audit version in CI to prevent false positives from advisory DB updates.

4.2 Supply Chain

Dependency Risk Level Notes
libaec-sys / libaec (SZIP) Medium C FFI; optional. Pin to a specific libaec version in the sys crate.
system-zlib / zlib-ng Medium C FFI; optional. Default path uses zlib-ng. Consider migrating to zlib-rs.
wgpu (GPU) Low Pure Rust + GPU driver ABI. Well-maintained.
pyo3 0.29 Low Recently updated; audit at each bump.
tokio (async feature) Low Well-audited, widely used.

4.3 cargo-deny Configuration

Add deny.toml at workspace root to enforce:

  • No duplicate dependencies at different semver versions
  • No unmaintained crates in the dependency tree
  • No licenses incompatible with MIT

5. Security Roadmap (Prioritized)

Item Priority Effort Impact
AES-256-GCM encryption at rest HIGH 23 weeks Confidentiality for .brain / sensitive memories
Ed25519 file signing HIGH 12 weeks Tamper detection for distributed .brain files
JNI Mutex wrapping MEDIUM 12 days UB prevention on multi-threaded Android
cargo-audit in CI MEDIUM 1 day Continuous dependency advisory monitoring
cargo-deny configuration LOW 1 day Dependency hygiene
Media reference sandboxing MEDIUM 1 week Path traversal prevention
Embedding-space anomaly detection MEDIUM 23 weeks Poisoning resistance beyond text patterns
Monotonic timestamp enforcement MEDIUM 35 days Temporal poisoning resistance
Overflow-checks = true in release HIGH 1 hour Defense in depth for format parsing
WAL commit marker for atomic rotation MEDIUM 1 week Consistency guarantee on crash during flush
SZIP fuzz target LOW 1 day C FFI boundary hardening