ScaleBun
Skip to article

Code signing

react-nativeDeveloper

Make OTA updates tamper-proof — generate an RSA-3072 key, embed the public half in the app, and have the device verify every bundle's signature natively before it runs. Keys, proof-of-possession, and enforcement.

Updated

Without signing, a device installs whatever bundle it is handed — a bundle swapped at the CDN or by a network attacker is indistinguishable from yours. Signing closes that gap: you sign each bundle with a private key, and the device verifies the signature against a trusted public key baked into the app before it runs a single line.

ScaleBun uses SB-OTA-RSA-SHA256-V1 — an RSA-3072 signature over the bundle's SHA-256. Verification happens in native code; JavaScript never holds a trusted key.

The model in one picture#

  • Private key — signs bundles. Lives on your machine / in CI. Never leaves it.

  • Public key — verifies signatures. Registered with ScaleBun and embedded in the app.

  • Key ID — a short label (e.g. prod-2026-01) that ties a signature to the right public key.

1. Generate a key#

Terminal
scalebun ota keys generate --key-id prod-2026-01 --app-id <appId>

This writes the private key to ./.scalebun/ota-signing-key.pem (keep it out of git — it's git-ignored for you), registers the public half with your app, and — because it's holding the private key at that moment — proves possession automatically, so the key comes out Active.

2. Embed the public key in the app#

Verification only works if the device has the public key. Add it as a native asset:

android/app/src/main/assets/scalebun_ota_keys.jsonJSON
{  "projectId": "<projectId>",  "keys": [    {      "keyId": "prod-2026-01",      "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBoj…AAE=\n-----END PUBLIC KEY-----"    }  ]}

Do the same for iOS, then rebuild and ship a native/store build.

3. Publish signed#

Once a key exists locally, ota publish signs automatically. Make it fail-closed so you never accidentally ship unsigned to a signature-enforcing app:

Terminal
scalebun ota publish --channel production --platform android --require-signing

The CLI confirms it:

Text
🔏 Signed with RSA key (SB-OTA-RSA-SHA256-V1)✅ Bundle v24 published successfully!

How enforcement behaves on-device#

Whether a device rejects unsigned bundles depends on whether it has a trusted key embedded:

App has a trusted key?Unsigned bundleWrong-key / tampered bundle
Yes (enforcing)Rejected — never installedRejected
NoInstalled (a warning, not a block)Installed

So the two ends work together: signing makes your publishes verifiable, and an enforcing build guarantees only your signed bundles ever run. The doctor command warns when no trusted key is embedded.

Key management#

Terminal
scalebun ota keys                     # list registered keys and their statusscalebun ota keys generate --key-id … # create + register + provescalebun ota keys verify              # prove possession of a pending key

Rotation and revocation are available from the dashboard's Signing keys view — a new key can be registered and rolled in without breaking devices that still trust the old one during the overlap.

Next#

  • CI/CD — keep the private key in CI secrets and sign there.

  • Channels & rollouts — why unsigned releases hit the approval gate.

Code signing · OTA updates · React Native SDK · ScaleBun