A high-assurance security simulation demonstrating capability-based sandboxing
using WASI 0.2, the Component Model, and a custom "Data Diode" runtime.
- The Scenario β What problem this solves
- Architecture β How it's built
- Quick Start β Run it locally
- Security Modes β Data Diode, Secure Channel, Lockdown, Breach
- 2oo3 Fault Tolerance β TMR voting demo
- Testing β Security invariants
- Production Path β Browser β Pi
- Hardware Demo β Raspberry Pi coming soon
"A 3rd-party sensor driver on an offshore oil rig attempts to read pressure data and secretly exfiltrate it to a vendor cloud. Our WASI runtime acts as a Data Diodeβallowing the read but blocking all outbound network connections."
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VANGUARD ICS GUARDIAN β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ wasi:filesystem βββββββββββββ β
β β Malicious β βββββββββββββββββββββββββββΆβ β ALLOW β β
β β Driver β βββββββββββββ β
β β (WASM) β wasi:sockets/tcp βββββββββββββ β
β β β ββββββββββββββββββββββββββΆβ β BLOCK β β
β βββββββββββββββ βββββββββββββ β
β β
β "Data Diode Mode: Read sensor β Block exfiltration" β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Component | Technology | Purpose |
|---|---|---|
| Guest | Rust β WASM | Untrusted sensor driver attempting data theft |
| Host | JavaScript (JCO) | The "Warden" runtime controlling capabilities |
| Interface | WIT (WASI 0.2) | Standard capability contracts |
| Dashboard | Leptos + Real WASM | Security console with live policy enforcement + 2oo3 TMR demo |
Vendor Build ββββΆ Vanguard Hub ββββΆ Edge Device
(Rust) (Ed25519 Sign) (Verify & Load)
Protects against SolarWinds-style supply chain attacks.
| Layer | Technology |
|---|---|
| Standard | WASI 0.2 (Preview 2) Component Model |
| Guest Language | Rust with cargo-component |
| Host Runtime | JavaScript via @bytecodealliance/jco |
| Dashboard | Leptos (Rust reactive web framework) |
| Interface Definition | WIT with wit-bindgen |
vanguard-ics-guardian/
βββ wit/ # Polyfill WIT interface definitions
β βββ world.wit # sensor-fs, sensor-net, sensor-utils
βββ guest/ # Rust WASM component (14.7 KB!)
β βββ src/lib.rs # The "attacker" with narration
βββ host/ # JavaScript runtime (the "warden")
β βββ shim/
β β βββ filesystem.js # Mock filesystem capabilities
β β βββ sockets.js # Data diode + secure channel
β βββ test/
β βββ shims.test.js # 17 unit tests
βββ cli/ # Node.js CLI demo (proves browser β edge portability)
β βββ run.mjs # Same WASM, measured outside browser
βββ dashboard/ # Leptos web UI
β βββ src/lib.rs # Reactive security console
β βββ styles.css # Mobile-responsive
βββ legacy/ # Docker "villains" for comparison
β βββ minimal.Dockerfile # ~200 MB (pyserial)
β βββ full.Dockerfile # ~800 MB (pandas, numpy)
β βββ ml.Dockerfile # ~2 GB (tensorflow)
βββ docs/
βββ ARCHITECTURE.md # WASI vs Docker rationale
βββ BRANCHING.md # Git workflow
βββ SECURITY.md # Security analysis + IEC 62443
Run the Dashboard:
# Install trunk (build tool for Leptos)
cargo install trunk
# Run dev server with live reload
cd dashboard && trunk serve
# Opens http://localhost:8080Run the Host Demo:
cd host && npm install && npm run demoRun the CLI Demo (proves browser β edge portability):
node cli/run.mjsπ Example CLI Benchmark Output
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VANGUARD ICS GUARDIAN - WASM PORTABILITY DEMO β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Same .wasm binary running in Node.js (proves browser β edge) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¦ Loading: malicious_driver.core.wasm (14.7 KB)
β±οΈ WASM Performance Metrics
ββββββββββββββββββββββββββββββββββββββββ
Load from disk: 2.15 ms
Compile (V8): 12.45 ms
Instantiate: 0.18 ms β This is what 2oo3 TMR measures!
ββββββββββββββββββββββββββββββββββββββββ
π Instantiation Benchmark (10 iterations)
ββββββββββββββββββββββββββββββββββββββββ
Min: 0.12 ms
Max: 0.31 ms
Avg: 0.18 ms
ββββββββββββββββββββββββββββββββββββββββ
π‘οΈ Security Policy Tests
ββββββββββββββββββββββββββββββββββββββββ
[DATA DIODE] FS: β ALLOW Net: β BLOCK
[SECURE CHAN] FS: β ALLOW Net: β internal only
[FULL LOCKDOWN] FS: β BLOCK Net: β BLOCK
ββββββββββββββββββββββββββββββββββββββββ
β
WASM component verified: same binary, same security, any runtime
| Mode | Filesystem | External | Internal | Description |
|---|---|---|---|---|
| π‘οΈ Data Diode | β Allow | β Block | β Block | Production mode |
| π Secure Channel | β Allow | β Block | β Allow | Internal SCADA only |
| π Full Lockdown | β Block | β Block | β Block | Zero trust |
| β Allow | β Allow | β Allow | Security failure demo |
Approved Internal Endpoints (Secure Channel mode):
10.0.0.50:502- SCADA server (Modbus)10.0.0.51:102- PLC gateway (S7)192.168.100.10:443- Data historian
Watch the malicious driver attempt data exfiltration under different security policies
Sensor read succeeds β | Network exfiltration blocked β
External blocked β | Internal SCADA endpoints allowed β
Zero trust: filesystem blocked, network blocked
What happens when security is misconfigured β data exfiltrated!
Runtime blocks execution when configuration is invalid
See the size difference in action
PLC Firmware: Docker 50 MB vs WASI 15 KB
Even at scale, WASI remains 500x smaller with 500x faster download
# JavaScript host tests (17 tests)
cd host && npm test
# Rust guest tests
cd guest && cargo testThis project demonstrates key principles from the IEC 62443 industrial cybersecurity standard, mapped to the Purdue Model:
| IEC 62443 Principle | Our Implementation | Code Reference |
|---|---|---|
| Zone & Conduit Model | OT zone (L0-2) isolated from IT (L4-5) via data diode | sockets.js |
| Unidirectional Gateway | Data Diode: read IN from sensors, block OUT to cloud | sockets.js |
| Defense in Depth | WASI capability model adds runtime-level security | filesystem.js |
| Least Privilege | Components only receive explicitly granted capabilities | WIT interface definitions |
| Secure by Default | Network access denied unless specifically whitelisted | Policy config in shims |
β οΈ Note: This is a demonstration of IEC 62443 concepts, not a certified implementation. Formal compliance requires third-party assessment.
For offshore oil rigs with limited satellite connectivity (~1 Mbps):
| Package | Docker (~500 MB) | WASI (~15 KB)* |
|---|---|---|
| Download Time | ~67 minutes | ~0.12 seconds |
| Network Impact | Saturates link | Negligible |
| Failover Speed | Minutes | Milliseconds |
*Actual measured size of our compiled malicious-driver component: 14.7 KB
This is why WASI matters for remote ICS environments.
The dashboard includes a Triple Modular Redundancy (TMR) visualization demonstrating WASM's fault tolerance advantages for safety-critical systems:
πΉ Watch: Fault Injection β Instant WASM Recovery
Click "Inject Fault" β WASM rebuilds in 0.2ms while Python takes 3+ seconds
| Metric | WASM Hot-Swap | Python Multiprocessing |
|---|---|---|
| Instance Rebuild | ~0.1-1 ms (measured) | 2-5 seconds |
| Frames During Fault | β Processed (2 healthy) | β Lost |
| Downtime | 0 ms (hitless) | 2-5 sec per restart |
Try it: Click "π₯ Inject Fault" in the live demo to corrupt one instance and watch:
- Majority voting still produces correct output (2oo3 consensus)
- WASM rebuilds the faulty instance in <1ms (real measurement shown)
- Python would lose in-flight frames during its 3+ second restart
π Aligns with IEC 61508 SIL 2/3 patterns for safety-critical systems.
π Want to see 2oo3 in action with attack simulations? Check out the companion project: Protocol Gateway Sandbox β Watch buffer overflows, truncated headers, and illegal function codes get isolated by WASM voting while Python crashes.
This project includes a comprehensive test suite using Vitest to verify the security invariants of the WASI shim. We test the Host implementation directly to ensure permissions are enforced before the Guest code even runs.
Running Tests:
cd host && npm testThe test suite (test/shims.test.js) verifies the critical states of the Data Diode:
| Scenario | Filesystem | Network | Expected Result |
|---|---|---|---|
| π‘οΈ Data Diode | β Allow | β Block | Read sensor, fail exfiltration |
| π§ Full Lockdown | β Block | β Block | All I/O rejected |
| π¨ Breach Simulation | β Allow | β Allow | Exfiltration succeeds (bad config) |
We also verify specific capability granularities:
- Path Isolation:
wasi:filesystemcannot access paths outside/mnt/ - IP Whitelisting: Even in "Secure Channel" mode, connections to unapproved IPs (like
1.1.1.1) are rejected at the shim level - Port Matching: Approved IPs must also use approved ports (e.g.,
10.0.0.50:502β,10.0.0.50:8080β)
π‘ The whitelist tests prove we implemented granular network policies, not just a simple on/off switch.
The WASM component is production-portableβthe same .wasm binary runs on multiple runtimes:
| Runtime | Platform | Use Case |
|---|---|---|
| Browser | Any modern browser | What we're demoing now (Leptos/Trunk) |
| Wasmtime | Linux, Windows, macOS | Server-side, Rust host |
| WasmEdge | ARM, RISC-V, Raspberry Pi | Edge devices, CNCF project |
| wasm3 | ESP32, STM32, Arduino | Resource-constrained MCUs |
| Component | This Demo | Production |
|---|---|---|
| WASM instantiation | β Real (<0.1ms) | Same or faster |
| 2oo3 voting logic | β Real | Same code |
| Capability enforcement | β Real | Same code |
| Modbus/Sensors | πΆ Mock shims | Replace with real I/O |
| Python restart times | πΆ Simulated | Based on benchmarks |
To deploy on real hardware:
- Replace JavaScript host with Rust + Wasmtime (same WASM component works)
- Swap mock shims for real protocol stacks (
tokio-modbus,rumqttc) - Add hardware watchdog for 2oo3 voter process
π The architecture patterns (capability isolation, 2oo3 voting) translate directly to real ICS deployments.
The same .wasm binary will run on real industrial hardware:
| Hardware | Sensors | What It Proves |
|---|---|---|
| Raspberry Pi 4 | DHT22, BME280, DS18B20 | Same WASM, real data, real security |
This works because the project follows the WASI 0.2 Component Model β a W3C standard that defines how WASM modules interact with the outside world through capability-based interfaces. The guest component only knows about abstract interfaces (sensor-fs, sensor-net), not whether it's running in a browser or on a Pi.
What stays the same:
guest.wasmβ identical binary, zero changes- WIT interface β same capability contracts
- Security model β data diode still blocks network
What we'll build:
- Rust host replacing JavaScript shims with real GPIO/I2C via
rppal sensor-fsimplementation reads actual sensor data instead of mock JSONsensor-utils::log()writes to RGB OLED display instead of console
π¬ Demo video coming soon β split-screen browser dashboard + physical Pi with sensors.
π Hardware Setup Guide β β Wiring diagrams, GPIO pinouts, implementation code
This project is part of the Reliability Triad β a portfolio demonstrating WASI 0.2 Component Model across security, protocol translation, and distributed consensus:
| Project | Focus | Demo |
|---|---|---|
| Vanguard ICS Guardian (this) | Capability-based sandboxing | Live Demo |
| Protocol Gateway Sandbox | Modbus/MQTT translation | Live Demo |
| Raft Consensus Cluster | Distributed consensus | Live Demo |
| Guardian-One | Hardware implementation | Private - in development |
Guardian-One is the hardware implementation of these concepts β a Rust/Wasmtime host running on Raspberry Pi 4 with BME280 sensors, SainSmart relays, and a 3-node Raft cluster for fault tolerance. Hardware demo coming soon.
- Architecture Deep Dive: WASI vs Docker comparison, Purdue Model, capability isolation
- Security Analysis: IEC 62443 alignment, attack surface reduction, what each technology solves
- Hardware Setup: Raspberry Pi wiring, sensor configuration, Rust host implementation
| Branch | Purpose | Deployment |
|---|---|---|
main |
Stable releases | Production |
develop |
Integration | Preview |
feature/* |
Feature work | β |
MIT Β© 2026
Built to demonstrate capability-based security for industrial control systems.








