Agent: 9 / Security Integration Analysis Date: 2026-02-20 Scope: Security posture assessment of ruvector and attack surface changes from sublinear-time-solver integration Classification: Internal Engineering Reference
- Current Security Posture of ruvector
- Attack Surface Changes from Integration
- WASM Sandbox Security
- Serialization and Deserialization Safety
- MCP Tool Access Control
- Dependency Supply Chain Risks
- Input Validation Requirements for Solver APIs
- Recommended Security Mitigations
The ruvector codebase demonstrates a mature, defense-in-depth security architecture across multiple layers:
Cryptographic Foundation (rvf-crypto)
- Ed25519 signature verification for all kernel packs and RVF segments (
/crates/rvf/rvf-crypto/src/sign.rs) - SHAKE-256 hash binding for tamper-evident witness chains (
/crates/rvf/rvf-crypto/src/witness.rs) - Attestation module with TEE platform support (SGX, SEV-SNP) including measurement-based key binding (
/crates/rvf/rvf-crypto/src/attestation.rs) - Domain separation in signature construction (
RVF-v1-segmentcontext string prevents cross-protocol replay) - Proper canonical serialization for signed data (avoids unsafe transmute, uses explicit byte layout)
WASM Kernel Pack Security (ruvector-wasm)
- Ed25519 manifest signature verification (
/crates/ruvector-wasm/src/kernel/signature.rs) - SHA256 hash-based kernel allowlist with per-kernel granularity (
/crates/ruvector-wasm/src/kernel/allowlist.rs) - Epoch-based execution interruption prevents infinite loops (
/crates/ruvector-wasm/src/kernel/epoch.rs) - Memory layout validation prevents overlapping regions and out-of-bounds access (
/crates/ruvector-wasm/src/kernel/memory.rs) - Resource limits per kernel (max memory pages, max epoch ticks, max table elements)
MCP Coherence Gate (mcp-gate)
- Three-tier decision system (Permit/Defer/Deny) with cryptographic witness receipts (
/crates/mcp-gate/src/tools.rs) - Hash-chain integrity verification for audit replay (
verify_chain_to) - Deterministic decision replay for forensic analysis
- Structured escalation protocol for deferred actions with timeout-to-deny default
Edge-Net Security
- Comprehensive relay security test suite covering 7 attack vectors (
/examples/edge-net/tests/relay-security.test.ts) - Task completion spoofing protection (assignment-based authorization)
- Replay attack prevention (duplicate completion rejection)
- Credit self-reporting rejection (server-side ledger authority)
- Per-IP connection limiting, rate limiting, message size limits
- WASM-based Ed25519 identity management with challenge-response verification (
/examples/edge-net/pkg/secure-access.js) - Adaptive security with self-learning attack pattern detection
- Adapter security with quarantine-before-activation, signature verification, and quality gates (
/examples/edge-net/pkg/models/adapter-security.js)
Storage Layer
- Path traversal prevention in
VectorStorage::new()(/crates/ruvector-core/src/storage.rs, line 78:path_str.contains("..")check) - Database connection pooling to prevent resource exhaustion
- Feature-gated storage (WASM builds use in-memory only)
SEC-W1: Server CORS Configuration is Fully Permissive
In /crates/ruvector-server/src/lib.rs (lines 85-88):
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);This allows any origin to make requests to the vector database API, enabling cross-site data exfiltration attacks. An attacker could embed JavaScript on any website that silently queries or modifies collections in a user's locally-running ruvector instance.
DREAD Score: D:6 R:9 E:8 A:7 D:9 = 7.8 (High)
SEC-W2: No Authentication or Authorization on REST API
The ruvector-server exposes collection CRUD and vector search/upsert endpoints with zero authentication. Any process with network access to port 6333 can:
- Create, list, and delete collections
- Insert arbitrary vectors
- Search and exfiltrate all stored data
This is acceptable for development but represents a critical gap for any deployment beyond localhost.
DREAD Score: D:8 R:10 E:10 A:8 D:10 = 9.2 (Critical)
SEC-W3: Unbounded Search Parameters
In /crates/ruvector-server/src/routes/points.rs, the SearchRequest.k parameter has a default of 10 but no upper bound. A malicious client can set k to usize::MAX, potentially causing:
- Memory exhaustion (allocating a result vector of billions of entries)
- CPU exhaustion (scanning entire index)
SEC-W4: Unsafe Code in SIMD and Arena Allocator
The ruvector-core contains 90 unsafe blocks across 4 files:
/crates/ruvector-core/src/simd_intrinsics.rs(40 occurrences) - SIMD intrinsics withassert_eq!length guards/crates/ruvector-core/src/arena.rs(23 occurrences) - Custom arena allocator with raw pointer arithmetic/crates/ruvector-core/src/cache_optimized.rs(19 occurrences)/crates/ruvector-core/src/quantization.rs(8 occurrences)
The SIMD code includes proper length assertions before unsafe operations, which is good. However, the arena allocator performs raw pointer arithmetic (chunk.data.add(aligned)) that relies on alignment invariants not enforced by the type system.
SEC-W5: Development-Mode Bypass Switches
Both the kernel signature verifier and the kernel allowlist provide insecure_* constructors:
KernelPackVerifier::insecure_no_verify()- Bypasses all signature checksTrustedKernelAllowlist::insecure_allow_all()- Bypasses all hash allowlist checks
These methods are documented with warnings but there is no compile-time gating (e.g., #[cfg(not(feature = "production"))]) to prevent accidental use in release builds.
SEC-W6: Default Backup Password in Edge-Net Identity
In /examples/edge-net/pkg/secure-access.js (line 141):
const password = this.options.backupPassword || 'edge-net-default-key';Identity key material is encrypted with a hardcoded default password. If no backup password is provided, any party who obtains the stored encrypted identity can decrypt the private key.
SEC-W7: Missing Input Validation on Collection Names
The CreateCollectionRequest.name field in /crates/ruvector-server/src/routes/collections.rs accepts arbitrary strings. This could lead to issues if collection names are used in file paths for persistent storage (directory traversal) or contain control characters.
| Component | Auth | Encryption | Integrity | Audit | Rating |
|---|---|---|---|---|---|
| ruvector-server | None | None (HTTP) | Serde validation | Trace logging | Low |
| ruvector-wasm kernel | Ed25519 + SHA256 | N/A | Hash allowlist | Epoch monitoring | High |
| mcp-gate | Action-based | N/A | Witness chain | Full replay | High |
| rvf-crypto | Ed25519 | TEE-bound keys | SHAKE-256 chain | Witness segments | Very High |
| edge-net | PiKey Ed25519 | Session-based | Challenge-response | Adaptive learning | High |
| ruvector-core | N/A | N/A | Dimension checks | None | Medium |
Integrating the sublinear-time-solver introduces the following new attack vectors:
AS-1: Express Server Endpoints
The solver includes an Express-based HTTP server with helmet and cors middleware. While helmet provides reasonable HTTP security headers, the integration creates a new network-accessible service that:
- Accepts solver problem definitions over HTTP
- Returns computed solutions
- Must validate all input parameters before passing to the Rust/WASM solver core
The net effect is a second HTTP service alongside ruvector-server, doubling the network-accessible API surface.
AS-2: WASM Sandbox Boundary
The solver executes optimization algorithms in WASM modules. Each WASM invocation represents a trust boundary crossing where:
- Input data flows from JavaScript host into WASM linear memory
- Computed results flow from WASM back to the host
- Shared memory regions must be validated on both sides
Unlike ruvector's existing WASM kernels (which have Ed25519 + allowlist verification), the solver's WASM modules need their own verification pipeline or must be integrated into ruvector's KernelManager framework.
AS-3: Serde Deserialization from External Sources
The solver uses serde for serializing/deserializing problem definitions and solution state. Deserialization of untrusted input is a well-known attack vector in Rust:
serde_json::from_strcan be safe but may allocate unbounded memory for deeply nested or large inputsrkyv(used elsewhere in ruvector) provides zero-copy deserialization which is more efficient but historically more prone to safety issuesbincodedeserialization can panic on malformed input if not configured with size limits
AS-4: Session Management State
The solver includes a session management module. Sessions introduce:
- Session fixation risks (predictable session IDs)
- Session hijacking via token theft
- Resource exhaustion through session flooding (creating millions of sessions)
- State consistency issues in multi-tenant scenarios
AS-5: MCP Tool Registration
If the solver registers as an MCP tool, it becomes callable by AI agents. This introduces:
- Agent-initiated solver invocations that could be computationally expensive
- Prompt injection attacks that cause agents to invoke the solver with adversarial inputs
- Recursive invocations if the solver itself uses MCP tools
| Surface | Pre-Integration | Post-Integration | Delta |
|---|---|---|---|
| HTTP Endpoints | 6 (ruvector-server) | 6 + N (solver) | +N |
| WASM Modules | Verified kernel packs | + Solver WASM | +1 boundary |
| Deserialization Points | serde_json (API) | + solver serde | +M |
| Session State | None (stateless) | Session manager | +1 state store |
| MCP Tools | 3 (mcp-gate) | 3 + solver tools | +K tools |
| Dependency Count | ~100 Rust crates | + solver deps | +D crates |
[External Client]
|
+-----------+-----------+
| |
[ruvector-server] [solver Express Server]
| |
[ruvector-core] [solver-core (WASM)]
| |
[redb/mmap storage] [solver session mgmt]
| |
[WASM kernel packs] [serde serialization]
| |
[mcp-gate] <--MCP--> [solver MCP tools]
Each arrow represents a trust boundary where input validation is required.
The ruvector WASM kernel system (/crates/ruvector-wasm/src/kernel/) implements a robust sandbox with multiple defense layers:
Layer 1: Supply Chain Verification
- Ed25519 signature verification of kernel pack manifests
- SHA256 hash verification of individual WASM kernel binaries
- Trusted key and hash allowlists with per-kernel granularity
Layer 2: Runtime Constraints
- Epoch-based execution interruption (configurable tick interval and budget)
- Maximum memory page limits (server: 1024 pages = 64MB; embedded: 64 pages = 4MB)
- Table element limits for indirect function calls
Layer 3: Memory Safety
MemoryLayoutValidatorprevents overlapping memory regions- Bounds checking on all descriptor offsets (
MemoryAccessViolationerror) - Aligned memory allocation (16-byte default)
- Read-only vs. writable region enforcement (output cannot overlap inputs)
Layer 4: Instance Isolation
- Each
WasmKernelInstancehas its own memory allocation - Epoch deadlines are per-invocation
- Instance pooling with configurable pool size
The sublinear-time-solver's WASM modules need equivalent protections. Key considerations:
3.2.1 Memory Bounds
Solver algorithms may require large working memory for optimization state. The default 64MB limit for server workloads may be insufficient for large problem instances. However, increasing memory limits increases the risk of memory exhaustion attacks.
Recommendation: Use dynamic memory limits based on problem size, with an absolute ceiling:
solver_memory_pages = min(problem_size_pages * 1.5, MAX_SOLVER_PAGES)
where MAX_SOLVER_PAGES is configurable but defaults to 2048 (128MB).
3.2.2 Execution Time Limits
Sublinear-time algorithms should complete faster than linear-time alternatives by definition. This creates a natural execution time bound that should be enforced:
- Expected: O(n^alpha) for alpha < 1
- Deadline: Set epoch budget proportional to
n^alpha * safety_factor - If deadline is exceeded, this indicates either a malicious input designed to trigger worst-case behavior or a bug
3.2.3 Solver-Specific WASM Risks
- Nondeterministic behavior: If the solver uses randomized algorithms, WASM determinism guarantees may not hold across platforms. This is acceptable for optimization but problematic for audit replay.
- Floating-point precision: WASM f32/f64 operations are IEEE 754 compliant but may produce different results on different CPUs due to fused-multiply-add variations. Solver results should include tolerance bounds.
- Stack overflow: Deeply recursive solver algorithms could exhaust the WASM stack. Wasmtime's configurable stack size should be explicitly set.
| Control | Current (ruvector) | Required (solver) | Gap |
|---|---|---|---|
| Signature verification | Ed25519 | Must integrate | Yes |
| Hash allowlist | Per-kernel SHA256 | Must integrate | Yes |
| Epoch interruption | Configurable | Required, problem-size-proportional | Partial |
| Memory limits | 64MB server / 4MB embedded | 128MB max, dynamic | Enhancement |
| Stack limits | Wasmtime default | Explicit 1MB limit | Yes |
| Instance isolation | Per-invocation | Per-invocation required | None |
| Determinism | Not enforced | Not required for optimization | None |
ruvector uses three serialization frameworks:
| Framework | Location | Purpose | Risk Level |
|---|---|---|---|
serde_json |
Server API, MCP protocol | JSON API requests/responses | Medium |
bincode (2.0 rc3) |
Storage, wire protocol | Binary vector encoding | High |
rkyv (0.8) |
Performance-critical paths | Zero-copy deserialization | Very High |
serde traits |
Everywhere | Derive macros for (de)serialization | Low |
serde_json is the safest of the three for untrusted input:
- Memory allocation is bounded by input size (no amplification attacks)
- Deeply nested JSON is limited by stack depth (configurable via
serde_json::Deserializer::disable_recursion_limit) - Unicode handling is correct per RFC 8259
Remaining risks:
- No built-in size limits. A multi-GB JSON payload will be allocated in full before being rejected by application-level validation. Mitigation: Use
hyper/axumbody size limits. - Numeric precision: JSON numbers are parsed as f64 or i64/u64. Large integers may lose precision silently.
bincode 2.0 (release candidate) is used with the serde feature for storage serialization. Key risks:
- Allocation amplification: A malicious bincode payload can declare a vector length of 2^64 elements, causing the allocator to attempt a multi-exabyte allocation. bincode 2.0 provides
Configuration::with_limit()to cap maximum allocation size. This MUST be used for any untrusted input. - Type confusion: bincode does not encode type information. If the wrong type is deserialized, the result is garbage data rather than an error. This can lead to logic errors in security-critical paths.
rkyv 0.8 provides zero-copy deserialization by directly interpreting byte buffers as Rust structs. This is extremely fast but carries significant safety implications:
- Alignment requirements: rkyv archived types must be properly aligned. Misaligned access on some architectures causes undefined behavior or hardware faults.
- Validation requirement: rkyv 0.8 provides
check_archived_root()for validating archived data before access. Skipping validation on untrusted input is equivalent to accepting arbitrary memory layouts as valid Rust structs. - Historical CVEs: Earlier rkyv versions had soundness issues. Version 0.8 addresses many of these but is still relatively new.
The sublinear-time-solver adds serde deserialization of:
- Problem definitions (graph structures, constraint matrices, objective functions)
- Solution state (intermediate solver state for session persistence)
- Configuration parameters
Critical requirement: All solver deserialization points MUST enforce:
- Maximum input size (reject payloads > configured limit before parsing)
- Maximum nesting depth (prevent stack overflow during parsing)
- Maximum collection sizes (prevent allocation amplification)
- Type validation (ensure deserialized types match expected schema)
Scenario D1: Memory Exhaustion via Vector Length
{
"graph": {
"nodes": 999999999,
"edges": []
}
}If the nodes count is used to pre-allocate a vector, this causes a ~4GB allocation attempt (999999999 * 4 bytes for f32 weights). Defense: Validate nodes <= MAX_SOLVER_NODES before allocation.
Scenario D2: Nested Object Bomb
{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":
... (1000+ levels deep)
}}}}}}}}}}}}}Deeply nested JSON can overflow the stack during recursive deserialization. Defense: Configure serde_json with recursion depth limits.
Scenario D3: Billion-Laughs Equivalent If the solver supports any form of reference-based serialization (which standard serde_json does not), a small input could expand into massive in-memory structures. Defense: Ensure no reference/entity expansion in deserialization.
The mcp-gate (/crates/mcp-gate/) implements a coherence gate with three tools:
| Tool | Purpose | Authorization | Audit |
|---|---|---|---|
permit_action |
Request permission for an action | Context-based (agent_id, session, prior_actions) | Witness receipt + hash chain |
get_receipt |
Retrieve audit receipt | Sequence number only | Read-only |
replay_decision |
Deterministic decision replay | Sequence number, optional chain verify | Read-only |
The authorization model is based on the TileZero coherence gate, which uses:
- Structural analysis: Graph cut values and partition stability
- Predictive analysis: Prediction set sizes and coverage targets
- Evidential analysis: E-value accumulation for evidence strength
AC-1: No Caller Authentication in MCP Protocol
The MCP server (/crates/mcp-gate/src/server.rs) accepts JSON-RPC messages over stdio without authenticating the caller. Any process that can write to the server's stdin can invoke tools. In the standard MCP deployment model (tool orchestrator spawns MCP server as child process), this is acceptable because the parent process is trusted. However:
- If the MCP server is exposed over a network (not standard but possible), there is zero authentication.
- The
agent_idfield inPermitActionRequestis self-reported and not verified.
AC-2: Receipt Enumeration
The get_receipt tool accepts a sequence number and returns the full receipt. An attacker who knows or can guess sequence numbers can enumerate all past decisions, extracting:
- Action IDs and types
- Target device and path information
- Agent and session identifiers
- Structural/predictive/evidential scores
This is an information disclosure risk if the MCP server is accessible to untrusted parties.
AC-3: No Rate Limiting on MCP Tools
Unlike the edge-net relay (which enforces per-node rate limits), the MCP server has no rate limiting. An agent could:
- Flood
permit_actionto cause computational denial-of-service - Rapidly enumerate
get_receiptwith sequential sequence numbers - Request
replay_decisionwithverify_chain: truefor expensive chain verification
If the sublinear-time-solver registers as MCP tools, the following risks emerge:
AC-4: Computational Cost Amplification
Solver invocations are inherently more expensive than gate decisions. A single solve_problem MCP call could consume seconds of CPU time and hundreds of megabytes of memory. Without per-agent resource quotas, a compromised or malicious agent could:
- Submit maximum-size problems continuously
- Exhaust all available compute resources
- Prevent legitimate operations from completing
AC-5: Problem Data as Attack Vector
If solver problem definitions are passed through MCP tool arguments (which are serde_json::Value), the deserialization risks from Section 4 apply directly in the MCP context. Agent-submitted JSON is inherently untrusted.
AC-6: Cross-Tool Information Flow
If the solver can invoke mcp-gate tools (or vice versa), there is a risk of:
- Privilege escalation (solver uses gate token to authorize its own actions)
- Information leakage (solver reads gate receipts to learn about other agents' actions)
- Circular dependencies (gate defers to solver, solver calls gate)
Agent --[MCP]--> mcp-gate (permit_action)
|
v
[Coherence Decision]
|
+------+----+----+------+
| | | |
Permit Defer Deny (log)
| |
v v
[Solver MCP Tool] [Escalation]
|
[Resource Quota Check]
|
[Input Validation]
|
[Solver Execution (sandboxed WASM)]
|
[Result + Witness Receipt]
Key additions for solver integration:
- Solver MCP tools MUST require a valid
PermitTokenfrom mcp-gate - Resource quotas MUST be enforced per-agent before solver invocation
- Solver results SHOULD generate witness receipts for audit
- Cross-tool calls MUST be prevented (unidirectional flow only)
The ruvector workspace contains approximately 100 direct Rust crate dependencies (12,884 lines in Cargo.lock). Key security-sensitive dependencies:
| Dependency | Version | Purpose | Supply Chain Risk |
|---|---|---|---|
ed25519-dalek |
(latest) | Cryptographic signatures | Low (well-audited) |
hnsw_rs |
0.3 (patched) | Vector indexing | Medium (patched locally) |
redb |
2.1 | Persistent storage | Low (Rust-native) |
rkyv |
0.8 | Zero-copy deserialization | Medium (complex unsafe) |
bincode |
2.0-rc3 | Binary serialization | Medium (pre-release) |
axum |
(latest) | HTTP server | Low (Tokio ecosystem) |
tower-http |
(latest) | HTTP middleware | Low (Tokio ecosystem) |
dashmap |
6.1 | Concurrent map | Low |
rayon |
1.10 | Parallel processing | Low (well-audited) |
simsimd |
5.9 | SIMD distance computation | Medium (C FFI) |
wasm-bindgen |
0.2 | WASM bindings | Low (Rust WASM ecosystem) |
@claude-flow/memory |
^3.0.0-alpha.7 | Agent memory (npm) | Medium (alpha pre-release) |
SC-1: Patched hnsw_rs
ruvector patches hnsw_rs locally (/patches/hnsw_rs) to resolve a rand version conflict (0.8 vs 0.9) for WASM compatibility. Local patches:
- Freeze the dependency at a known state (good for reproducibility)
- Prevent receiving upstream security fixes automatically (bad for security)
- Require manual review and re-patching when upstream publishes fixes
SC-2: bincode Pre-Release
Using bincode 2.0.0-rc3 means:
- API may change before stable release
- Less community testing than stable versions
- Potential for undiscovered safety issues
SC-3: simsimd C FFI Boundary
simsimd (5.9) provides C-language SIMD implementations called via FFI. This introduces:
- Memory safety risks at the FFI boundary
- Potential for ABI mismatches if simsimd is compiled with different flags
- Dependencies on system-level C library versions
SC-4: npm Dependency Tree
The npm workspace (ruvector-node, ruvector-wasm, etc.) brings a separate dependency tree. Notable overrides in package.json:
"overrides": {
"axios": "^1.13.2",
"body-parser": "^2.2.1"
}These overrides suggest known vulnerabilities in transitive dependencies that required manual pinning.
The sublinear-time-solver adds:
| Dependency | Risk Assessment |
|---|---|
| Express.js | Low risk (mature, well-maintained) |
| helmet | Low risk (security-focused, minimal surface) |
| cors (npm) | Low risk (widely used) |
| serde (Rust) | Already present in ruvector |
| wasm-bindgen (Rust) | Already present in ruvector |
New unique risks from solver dependencies:
- Express middleware chain introduces potential request smuggling if reverse-proxied
- Any solver-specific npm packages must be audited for supply chain attacks
- MIT/Apache-2.0 dual licensing is compatible with ruvector's MIT license (no legal risk)
- Lock files: Ensure both
Cargo.lockandpackage-lock.jsonare committed and used in CI - Audit automation: Run
cargo auditandnpm auditin CI pipeline - Dependency review: Use
cargo-denyto enforce license compliance and ban known-vulnerable crates - SBOM generation: Generate Software Bill of Materials for all builds
- Upstream monitoring: Set up alerts for upstream security advisories on critical dependencies
- Minimal solver dependencies: Prefer solver implementations that minimize additional dependency count
All solver API inputs must be validated before processing. The following validation rules apply:
7.1.1 Graph/Network Inputs
| Parameter | Type | Constraint | Rationale |
|---|---|---|---|
node_count |
usize | 1 <= n <= MAX_NODES (default: 10,000,000) | Prevent memory exhaustion |
edge_count |
usize | 0 <= e <= MAX_EDGES (default: 100,000,000) | Prevent memory exhaustion |
edge_weights |
f32/f64 | Finite, not NaN, not Inf | Prevent arithmetic errors |
node_ids |
string | <= 256 chars, alphanumeric + hyphens | Prevent injection |
adjacency |
sparse | e <= n * (n-1) / 2 (undirected), e <= n * (n-1) (directed) | Graph consistency |
7.1.2 Optimization Parameters
| Parameter | Type | Constraint | Rationale |
|---|---|---|---|
max_iterations |
u64 | 1 <= iter <= MAX_ITER (default: 1,000,000) | Prevent infinite computation |
tolerance |
f64 | 0 < tol <= 1.0 | Meaningful convergence criterion |
timeout_ms |
u64 | 100 <= t <= MAX_TIMEOUT (default: 300,000) | Prevent resource lock |
seed |
u64 | Any | No constraint needed |
alpha (sublinearity) |
f64 | 0 < alpha < 1 | Must be sublinear by definition |
7.1.3 Vector/Matrix Inputs
| Parameter | Type | Constraint | Rationale |
|---|---|---|---|
dimension |
usize | 1 <= d <= MAX_DIM (default: 65,536) | Prevent memory exhaustion |
values |
Vec | len == declared dimension, all finite | Memory safety, arithmetic safety |
matrix |
nested Vec | rows * cols <= MAX_MATRIX_ELEMENTS | Memory bounds |
| Parameter | Type | Constraint | Rationale |
|---|---|---|---|
session_id |
string | UUID v4 format, server-generated only | Prevent session fixation |
session_ttl |
u64 | 60 <= ttl <= 86400 seconds | Prevent permanent sessions |
max_sessions_per_client |
usize | Default: 10 | Prevent session flooding |
session_data_size |
usize | <= MAX_SESSION_DATA (default: 10MB) | Prevent storage exhaustion |
| Endpoint | Rate Limit | Burst | Rationale |
|---|---|---|---|
| Problem submission | 10/minute per client | 3 | Prevent compute exhaustion |
| Solution retrieval | 100/minute per client | 20 | Allow polling |
| Session operations | 30/minute per client | 5 | Prevent session flooding |
| Health/status | 60/minute per client | 10 | Allow monitoring |
// Recommended validation pattern for solver inputs
pub fn validate_problem_input(input: &ProblemDefinition) -> Result<(), ValidationError> {
// 1. Size bounds
if input.node_count > MAX_NODES {
return Err(ValidationError::TooLarge {
field: "node_count",
max: MAX_NODES,
actual: input.node_count,
});
}
// 2. Numeric sanity
for weight in &input.edge_weights {
if !weight.is_finite() {
return Err(ValidationError::InvalidNumber {
field: "edge_weights",
reason: "non-finite value",
});
}
}
// 3. Structural consistency
if input.edge_count > input.node_count * (input.node_count - 1) {
return Err(ValidationError::InconsistentGraph {
reason: "more edges than possible for given node count",
});
}
// 4. Parameter ranges
if input.alpha <= 0.0 || input.alpha >= 1.0 {
return Err(ValidationError::OutOfRange {
field: "alpha",
min: 0.0,
max: 1.0,
actual: input.alpha,
});
}
Ok(())
}MIT-1: Add Authentication to ruvector-server
Implement API key or JWT-based authentication for the REST API. At minimum:
- Require
Authorization: Bearer <token>header on all mutating endpoints - Support API key rotation without server restart
- Log authentication failures with client IP
// Suggested middleware addition
async fn auth_middleware(
State(state): State<AppState>,
request: Request,
next: Next,
) -> Result<Response, StatusCode> {
let token = request.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "));
match token {
Some(t) if state.verify_token(t) => Ok(next.run(request).await),
_ => Err(StatusCode::UNAUTHORIZED),
}
}MIT-2: Restrict CORS Configuration
Replace Any CORS origins with an explicit allowlist:
let cors = CorsLayer::new()
.allow_origin(AllowOrigin::list([
"http://localhost:3000".parse().unwrap(),
"http://127.0.0.1:3000".parse().unwrap(),
]))
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers([AUTHORIZATION, CONTENT_TYPE]);MIT-3: Add Request Body Size Limits
Add axum body size limits to prevent memory exhaustion:
router = router.layer(DefaultBodyLimit::max(10 * 1024 * 1024)); // 10MB maxMIT-4: Bound Search Parameters
Add upper bounds to SearchRequest.k and all vector dimensions:
const MAX_K: usize = 10_000;
const MAX_VECTOR_DIM: usize = 65_536;
// In search handler:
let k = req.k.min(MAX_K);
if req.vector.len() > MAX_VECTOR_DIM {
return Err(Error::InvalidRequest("vector dimension too large".into()));
}MIT-5: Integrate Solver WASM into Kernel Pack Framework
The solver's WASM modules should be treated as kernel packs:
- Sign solver WASM modules with Ed25519
- Add solver kernel hashes to the
TrustedKernelAllowlist - Execute solver WASM through the
KernelManagerwith epoch deadlines - Set memory limits proportional to problem size with an absolute ceiling
MIT-6: Enforce Serialization Size Limits
For all deserialization of untrusted input:
// For bincode:
let config = bincode::config::standard()
.with_limit::<{ 10 * 1024 * 1024 }>(); // 10MB max
// For serde_json, use axum body limits + custom deserializer:
let value: ProblemDefinition = serde_json::from_slice(&body)?;
validate_problem_input(&value)?; // Application-level validationMIT-7: Add MCP Tool Rate Limiting
Implement per-agent rate limiting for MCP tools:
struct RateLimiter {
windows: DashMap<String, (Instant, u32)>,
max_per_minute: u32,
}
impl RateLimiter {
fn check(&self, agent_id: &str) -> Result<(), McpError> {
let mut entry = self.windows.entry(agent_id.to_string())
.or_insert((Instant::now(), 0));
if entry.0.elapsed() > Duration::from_secs(60) {
*entry = (Instant::now(), 0);
}
entry.1 += 1;
if entry.1 > self.max_per_minute {
return Err(McpError::RateLimited);
}
Ok(())
}
}MIT-8: Require PermitToken for Solver MCP Tools
Solver MCP tools should require a valid PermitToken from the coherence gate:
pub async fn solve_problem(&self, call: McpToolCall) -> Result<McpToolResult, McpError> {
// 1. Extract and validate permit token
let token = call.arguments.get("permit_token")
.ok_or(McpError::InvalidRequest("missing permit_token".into()))?;
self.gate.verify_token(token).await?;
// 2. Validate problem input
let problem: ProblemDefinition = serde_json::from_value(call.arguments.clone())?;
validate_problem_input(&problem)?;
// 3. Execute solver with resource limits
self.execute_solver(problem).await
}MIT-9: Compile-Time Gating of Insecure Modes
Add feature gates to prevent insecure constructors in release builds:
#[cfg(any(test, feature = "insecure-dev"))]
pub fn insecure_no_verify() -> Self { ... }
#[cfg(not(any(test, feature = "insecure-dev")))]
pub fn insecure_no_verify() -> Self {
compile_error!("insecure_no_verify is not available in production builds");
}MIT-10: Remove Hardcoded Default Backup Password
Replace the hardcoded default password in edge-net identity management:
// Instead of:
const password = this.options.backupPassword || 'edge-net-default-key';
// Require explicit password:
if (!this.options.backupPassword) {
throw new Error('backupPassword is required for identity persistence');
}MIT-11: Validate Collection Names
Add collection name validation to prevent injection and path traversal:
fn validate_collection_name(name: &str) -> Result<(), Error> {
if name.is_empty() || name.len() > 128 {
return Err(Error::InvalidRequest("collection name must be 1-128 chars".into()));
}
if !name.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_') {
return Err(Error::InvalidRequest("collection name must be alphanumeric".into()));
}
Ok(())
}MIT-12: Add Solver-Specific Audit Trail
Extend the witness chain to include solver invocations:
let witness_entry = WitnessEntry {
prev_hash: previous_hash,
action_hash: shake256_256(&solver_invocation_bytes),
timestamp_ns: current_time_ns(),
witness_type: WITNESS_TYPE_SOLVER_INVOCATION,
};MIT-13: Fuzz Testing for Deserialization Paths
Set up cargo-fuzz targets for all deserialization entry points:
serde_json::from_str::<ProblemDefinition>()bincode::decode_from_slice::<VectorEntry>()KernelManifest::from_json()- All
decode_*functions in rvf-crypto
MIT-14: Security Headers for Solver Express Server
Verify that the solver's Express server includes:
app.use(helmet({
contentSecurityPolicy: { directives: { defaultSrc: ["'self'"] } },
crossOriginEmbedderPolicy: true,
crossOriginOpenerPolicy: true,
crossOriginResourcePolicy: { policy: "same-origin" },
hsts: { maxAge: 31536000, includeSubDomains: true },
referrerPolicy: { policy: "no-referrer" },
}));MIT-15: unsafe Code Audit
Commission a focused audit of the 90 unsafe blocks in ruvector-core:
/crates/ruvector-core/src/simd_intrinsics.rs(40 blocks) - SIMD intrinsics/crates/ruvector-core/src/arena.rs(23 blocks) - Arena allocator/crates/ruvector-core/src/cache_optimized.rs(19 blocks) - Cache-optimized structures/crates/ruvector-core/src/quantization.rs(8 blocks) - Quantization
Priority areas: arena allocator pointer arithmetic and cache-optimized data structures where bounds checking may be insufficient.
MIT-16: TLS for All Network Communication
Both ruvector-server and the solver Express server should support TLS:
- Require TLS for non-localhost deployments
- Support mTLS for service-to-service communication
- Use certificate pinning for MCP tool connections
| Threat | Category | Risk | Mitigation |
|---|---|---|---|
| Attacker submits malicious problem to solver via API | Tampering | High | MIT-6, MIT-4, Section 7 validation |
| Attacker bypasses solver resource limits via crafted WASM | Elevation of Privilege | High | MIT-5 (kernel pack framework) |
| Attacker enumerates gate decisions via receipt API | Information Disclosure | Medium | MIT-7 (rate limiting), AC-2 auth |
| Attacker floods solver with expensive problems | Denial of Service | High | MIT-7, MIT-8, Section 7.3 rate limits |
| Attacker replays valid permit token for unauthorized solver use | Spoofing | Medium | Token TTL, nonce in token |
| Agent makes solver calls without audit trail | Repudiation | Medium | MIT-12 (solver audit trail) |
| Attacker modifies solver WASM binary | Tampering | High | MIT-5 (Ed25519 + allowlist) |
| Compromised dependency injects malicious code | Tampering | Medium | MIT-14, Section 6.4 supply chain |
- All solver API endpoints reject payloads > 10MB
-
kparameter in search is bounded to MAX_K - Collection names are validated (alphanumeric + hyphens, max 128 chars)
- Solver WASM modules are signed and allowlisted
- Solver WASM execution has epoch deadlines proportional to problem size
- Solver WASM memory is limited to MAX_SOLVER_PAGES
- MCP solver tools require valid PermitToken
- MCP tools have per-agent rate limiting
- Deserialization uses size limits (bincode
with_limit, JSON body limit) - Session IDs are server-generated UUIDs (not client-provided)
- Session count per client is bounded
- Express server has helmet with strict CSP
- CORS is restricted to known origins (not
Any) - Authentication is required on mutating endpoints
- All
unsafecode has been reviewed for solver integration paths -
cargo auditandnpm auditpass with no critical vulnerabilities - Fuzz testing targets exist for all deserialization entry points
- Solver results include tolerance bounds for floating-point results
- Cross-tool MCP calls are prevented (unidirectional flow)
- Witness chain entries are created for solver invocations