Skip to main content

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:

  1. Loads the manifest (build/integrity.json) and the public key (build/integrity.pub.pem).
  2. Verifies the RSA-PSS signature over the canonical (sorted) file-hash map.
  3. 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

The integrity check also reports unknown files — files under the watched roots that aren’t in the manifest. This isn’t a tamper finding (often it’s a misconfigured build), but it surfaces in the Diagnostics panel so the team notices.

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() or eval().
  • 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-brk flags 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

Client-side anti-tamper is a cost shift, not a cryptographic guarantee. A determined attacker with physical access to your machine + an offline copy of the binary can rebuild and re-sign. The point of the heuristics is to make casual reverse engineering significantly harder — the cryptographic guarantees live in the signed receipts and the backend-side response signer.

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 reports go to security@midcore.ai. We acknowledge within 24 hours and patch within the standard responsible-disclosure window.