SECURITY · MARKETPLACE · 2026-05-08 · Createrun Engineering · 6 min read

Marketplace dual-signature explained

Why does the Createrun Marketplace sign every CRApp twice? Because one signature only proves authorship — it doesn't prove anyone reviewed the package.

The threat model

A CRApp travels a long path between the developer who wrote it and the customer who installs it. Pick any link in that chain — a hostile mirror, a corrupted CDN node, an insider with edit access to a build artifact bucket, an MITM proxy on the install network — and you have an attacker capable of shipping a tampered package downstream.

Single-signature distribution doesn't prevent this well. If the developer signs the package and an attacker has compromised the distribution channel, the attacker can either: (a) sign their malicious version with a different key (different fingerprint, but the customer doesn't necessarily check); (b) wait for the developer to sign a new version, replace the bytes, and rely on customers re-using cached signature checks.

We wanted a model where an integrity check at install time catches tampering even when one party in the chain is compromised.

The dual-signature design

Every CRApp .crpck carries two ECDSA P-256 signatures:

  1. Developer signature.The publisher signs the .crpck with their private key as the last step of the build. ECDSA P-256 on the .NET BCL — no third-party crypto dependency. The corresponding public key (SPKI) is registered with the Marketplace at developer enrolment.
  2. Marketplace signature.After review (automated checks + human review for paid CRApps), the Marketplace re-signs the same .crpck with its own ECDSA P-256 key. The Marketplace's public key is well-known and pinned at install time on every Createrun instance.

The verification logic at install:

verify(developerSig, package, developerPubKey)   // proves authorship
verify(marketplaceSig, package, marketplacePubKey) // proves Marketplace approval
if (developerKey not in registeredPublishers)
    fail "unknown publisher"
if (signedTimestamp before reviewQueueExit)
    fail "signature predates review"

What this catches

  • Hostile mirror.Replaces the .crpck with a malicious version. The Marketplace signature fails — the attacker doesn't have the Marketplace key.
  • MITM on install.Same — fails Marketplace signature check.
  • Compromised CDN node.Same.
  • Tampered version on Marketplace storage.If the attacker bypasses Marketplace and replaces a published .crpck with a different one signed by the Marketplace... they'd need to compromise Marketplace's private key, which lives in the encrypted Configuration Store and never leaves the signing service. Even then, the audit trail at the Marketplace would catch the unauthorised re-sign.
  • Legitimate developer's key compromise.Detected at the next Marketplace review — reviewers see unexpected publisher activity. License revocation invalidates affected installs via the IDM revocation list pulled by every Setup activation.

What it doesn't catch (yet)

Dual-signature is integrity. It's not source-code review. A CRApp could be perfectly signed and still contain bugs or hostile logic the publisher chose to ship. We rely on:

  • Marketplace review.Static analysis + behavioural sandboxing for paid CRApps.
  • Per-tenant isolation at the runtime.A bad CRApp in one tenant cannot reach data in another — Authorization XML store + multi-tenant claim checks enforce the boundary.
  • Sub-resource integrity for assets.CRApps that pull external assets (fonts, scripts) at runtime are required to declare SRI hashes — a roadmap item.

Implementation notes

The signing key ceremony is real. Marketplace's ECDSA P-256 private key is generated inside the signing service and stored in the encrypted Configuration Store; it never exists in plaintext on any developer machine. Signing happens via internal API calls from the Marketplace review service. Audit logs record every sign operation.

Developer keys can be self-managed (most common — ssh-keygen-style) or managed via your own secret store. We don't see your developer private key.

Operational consequences

Two-week sprints and dual-sig package distribution. Connected instances check for signed updates on a customer-controlled schedule; installation remains customer-triggered and reversible, and botched releases roll back (smoke-fail revert, by design). Air-gapped instances import signed packages manually — Createrun never opens an inbound control channel. License JWTs bind to a single instance fingerprint — copy-paste re-use across instances fails, preventing one compromised credential from spreading horizontally.

If you're integrating Createrun with your own distribution pipeline, the signed package manifest format documents the byte-level layout.Security & Trustcovers the full crypto stack;Marketplacecovers publisher economics.

Back to blog