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]>
13 KiB
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) andclawhdf5-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:
- Store a random 96-bit nonce per HDF5 chunk alongside the chunk data.
- Encrypt each chunk's decompressed data with AES-256-GCM before writing; decrypt on read.
- Encrypt WAL entries with the same key.
- Store a key-derivation salt in the file header; derive the working key from a user passphrase via Argon2id.
- 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: 2–3 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:
- Ed25519 signatures: Add an
[package] signing_keyfield toMemoryConfig. 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. - ClawBrainHub trust chain: The registry should sign
.brainfiles with a registry key. ClawHDF5 should ship aclawhdf5-cli verifycommand that checks the registry signature.
Crates: ed25519-dalek (pure Rust, widely audited).
Effort estimate: 1–2 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:
- 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.
- 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.
- 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: 1–2 weeks for Mahalanobis detection; 2–3 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:
- Signed timestamps: When file signing is enabled (see 3.2), include timestamps in the signed data.
- 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: 1–2 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:
- Allowlist-based path validation: The agent should only resolve
MediaRef::Pathentries that are within a configuredmedia_sandbox_dir. - Canonicalization before resolution: Always call
std::fs::canonicalizebefore resolving a path, then check it is within the sandbox. - URL scheme allowlist:
MediaRef::Urlshould only allowhttps://by default. Rejectfile://,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:
- The current implementation validates
cd.len() >= 5and checksbits_per_sample > 0 && <= 32. Add a check thatchunk_sizeis non-zero and does not exceed a maximum (e.g., 512 MiB). - Consider wrapping the
aec_buffer_decodecall instd::panic::catch_unwind(if the C library signals errors via signals, not return codes — verify with libaec docs). - Add a fuzz target (
fuzz_szip_decompress) when theszipfeature 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:
- 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. - Very long string attributes: The
local_heap.rsfixes guard overflow arithmetic but there is no explicit cap on total string heap size. AddMAX_STRING_HEAP_BYTES. - 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-auditto CI:cargo audit --deny warningsafter every dependency update. - Pin a
cargo-auditversion 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
unmaintainedcrates in the dependency tree - No licenses incompatible with MIT
5. Security Roadmap (Prioritized)
| Item | Priority | Effort | Impact |
|---|---|---|---|
| AES-256-GCM encryption at rest | HIGH | 2–3 weeks | Confidentiality for .brain / sensitive memories |
| Ed25519 file signing | HIGH | 1–2 weeks | Tamper detection for distributed .brain files |
JNI Mutex wrapping |
MEDIUM | 1–2 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 | 2–3 weeks | Poisoning resistance beyond text patterns |
| Monotonic timestamp enforcement | MEDIUM | 3–5 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 |