Security
Local-first compute shifts work onto your machine. That’s good for cost and privacy but it also means we ship more code + signed receipts into a less-controlled environment. This page explains the security posture that ships with the Midcore Shell and what each layer does.
1. ASAR integrity
Every production build of the shell ships with an integrity manifest signed by Midcore’s signing key. On launch the main process:
- Loads the manifest (
build/integrity.json) and the public key (build/integrity.pub.pem). - Verifies the RSA-PSS signature over the canonical (sorted) file-hash map.
- SHA-256s every listed file. If any hash diverges, or the signature fails, the shell refuses to start.
This means a third party can’t silently swap a runner or main-process module without forging the signature — which would require the private key, which lives only on the signing pipeline (under Azure Trusted Signing’s CSP in production).
Drift detection
2. Signed-WASM verification
Any WASM the local compute plane loads (DuckDB, llama.cpp, onnxruntime-web, tree-sitter, ffmpeg.wasm) must ship with a sidecar .sig file containing an RSA-PSS signature over the WASM bytes, verified against the same public key. The runner refuses to instantiate unsigned or mis-signed modules in production.
This protects against (a) supply-chain attacks where a public WASM is swapped at the registry, and (b) operator-side tampering where a privileged user tries to replace a runner with their own.
3. Sandboxed Worker pool
Local runners execute in Node Worker threads with:
- eval: false — no attacker-controlled task descriptor can smuggle code via
Function()oreval(). - Bundle-only spawn paths — the pool refuses any runner module path outside the ASAR-bundled
local-compute/runners/tree. - Resource limits — 1 GB old-gen, 256 MB young-gen, 64 MB code range per worker. A runaway runner is killed, not the renderer.
- No auth tokens in workers — cloud calls (which carry the auth bearer) happen only on the main thread. Workers can’t exfil what they can’t see.
4. Anti-tamper heuristics
Production builds reject the easy reverse-engineering paths:
- Devtools opened in a packaged build are immediately closed.
--remote-debugging-port,--inspect, and--inspect-brkflags are detected at boot.- A Node inspector listening on the process throws a tamper finding.
- Every finding fires a system-domain evidence node so the audit chain records the attempt.
Heuristics, not guarantees
5. Signed cloud receipts
Every cloud-billed operation produces a receipt signed by the backend response signer. The shell verifies the signature before writing the receipt onto your project audit ledger:
- The receipt covers
id | operation | tenant_id | actual_cents | finalized_at_ms. - The audit ledger entry is hash-chained: subsequent receipts carry the previous entry as a parent.
- An offline verifier can replay any project’s audit chain end-to-end without contacting Midcore servers.
This is the auditability story: not just for regulators, but for your own diff — “what did we actually pay for last month” reconstructs offline from the chain.
What we deliberately don’t do
Two anti-features worth naming:
- We don’t encrypt the renderer bundle. Symbol obfuscation, JS bytecode packing, and runtime decryption all add friction for legitimate users (slower boot, debug failures, anti-virus false positives) and only minor friction for an attacker. Source maps are stripped, but the underlying JS is readable.
- We don’t fingerprint your hardware. The capability probe reads CPU count, RAM, and GPU vendor but doesn’t derive a unique identifier. License binding works through the tenant key, not the machine.
If you found something
security@midcore.ai. We acknowledge within 24 hours and patch within the standard responsible-disclosure window.