Technical guide

How to prevent mods and hacks that require re-signing iOS apps

Stop re-signed iOS app mods from reaching your service: App Attest on the server, Team ID and provisioning checks in the app, and tested signing changes.

  • Re-signing changes identity

    A modded copy cannot carry your signature. It runs under another Team ID, and that difference is what you check.

  • Refuse it at the server

    App Attest binds every sensitive request to your App ID. A re-signed copy cannot produce an assertion your server accepts.

  • Rehearse your own changes

    Certificate renewals, new channels and EU distribution change signing too. Record them so legitimate releases never look like mods.

You cannot stop someone from modifying a copy of your iOS app, but you can stop that copy from working against your service. Every mod must be re-signed, and re-signing changes the app’s identity: a different Team ID, a provisioning profile that App Store builds do not have, and keys that do not match your App ID. Use App Attest so your server refuses requests that do not come from your genuine app. Add in-app checks on Team ID, bundle ID and provisioning, and a response policy for what the app does when they fail. Then record your own legitimate signing changes so they are never mistaken for mods.

How re-signed mods reach devices

An App Store binary is encrypted and signed by Apple for your Team ID. To modify it, an attacker decrypts a copy, changes code or injects a library, and signs the result with a certificate they control. Common routes:

  • Free developer accounts. Anyone with an Apple ID can sign an app for their own device. The profile expires after seven days, so sideloading tools re-sign it repeatedly.
  • Paid developer certificates. Ad hoc profiles install on registered devices; some mod services sell device registrations.
  • Enterprise certificates. Certificates meant for in-house distribution are misused to install mods on any device until Apple revokes them.
  • Desktop sideloading tools. These automate signing with the user’s own Apple ID and refresh the app before the profile expires.

EU alternative distribution

In the European Union, iOS also allows alternative app marketplaces and web distribution. These apps are still signed with the developer’s own certificate and notarised by Apple, so a marketplace cannot ship a modded copy under your Team ID. Expect legitimate installs from these channels if you use them, and record them as approved. On iOS in the EU, MarketplaceKit’s AppDistributor reports whether the App Store, TestFlight, a marketplace or web distribution installed the app.

Refuse re-signed copies on the server with App Attest

App Attest is the strongest control because it runs outside the device’s reach. The app generates a key with DCAppAttestService, Apple attests it, and your server records the public key. The attestation includes a hash of your App ID, which is your Team ID plus bundle ID. A re-signed copy runs under a different Team ID, so its attestation fails your check, or it cannot obtain one at all.

  1. Check DCAppAttestService.shared.isSupported. If it is false, apply your unavailable-evidence policy.
  2. Call generateKey(), then attestKey(_:clientDataHash:) with a hash of a single-use server challenge.
  3. On the server, validate the attestation as Apple documents, including the RP ID hash of your exact App ID and the production environment.
  4. For each sensitive request, verify an assertion from generateAssertion(_:clientDataHash:) that covers the request and a fresh challenge, and require the counter to increase.

Requests without a valid assertion do not reach sensitive operations. The full procedure is in how to verify mobile app attestation.

Detect re-signing inside the app

In-app checks catch a mod early and let the app respond. A mod author can patch them, so protect the code that runs them and never rely on them alone.

CheckWhat a genuine App Store install showsWhat a re-signed copy usually shows
Team IDYour Team ID as the prefix of the keychain access groupAnother Team ID
Bundle IDBundle.main.bundleIdentifier equals your IDSame or changed ID
embedded.mobileprovisionNot present in the app bundlePresent, naming another team
Binary encryptioncryptid set to 1 in the LC_ENCRYPTION_INFO_64 load commandcryptid 0 after decryption
Associated domainsUniversal links and shared web credentials workFail, because your apple-app-site-association file lists only your App ID

To read the Team ID, add a keychain item and query its kSecAttrAccessGroup attribute; the value starts with the Team ID. Development, ad hoc and enterprise builds of your own app contain embedded.mobileprovision, so run the provisioning check only in App Store builds.

Otukan detects app tampering and unauthorised re-signing in protected iOS applications within the configured control scope, and the app applies the response you set per flow. For the product boundary, see repackaging and re-signing detection and iOS app anti-tampering.

Record your own signing authority

Create a release identity record: app owner, channel, App ID, signing certificate, profile and entitlements, including every app extension. Keep private keys inside your approved signing environment. Otukan fits your existing build and release pipeline while signing keys stay with your team.

ItemRecordAvoid assuming
Signing authorityWho may approve and sign a releaseAny valid signature means you approved it
ProvisioningProfile purpose and validity per channelOne profile serves every channel
EntitlementsApp Attest environment and other capabilities, per targetA capability in the project is in the signed output
DistributionChannel and final delivered artefactA development build stands in for the store build

Inspect the final signed app with codesign and compare entitlements and Team ID with the record.

Test with an authorised lab

Use an app you own, test accounts and non-production services. Write the expected result before each run.

  1. Install the App Store build on physical devices and run sign-in, update, extension entry points and the sensitive action.
  2. Re-sign a lab copy with a different team’s development certificate. Record whether it installs and launches, separately from any detection.
  3. If it reaches the flow, record the in-app signal, the configured response and the server’s App Attest decision.
  4. Repeat with an ad hoc copy and with a copy that changes only the bundle ID.

A copy that iOS refuses to install is platform evidence, not a detection result. Simulator runs are recorded separately and do not replace signed-device tests.

Rehearse legitimate changes

Renew a distribution certificate, add a new channel and ship a corrective release. Confirm installed versions keep working and App Attest keys stay valid. Identify where an expired or mismatched profile fails: packaging, install, launch or a protected operation.

  • App Attest assertions are required for every sensitive endpoint.
  • In-app checks run only in the builds they apply to.
  • Approved channels, including EU distribution if used, are recorded.
  • Certificate and profile changes have an owner and a review trail.
  • Install, update, sign-in and sensitive-flow regressions pass.

For Android, see how to detect repackaging in Android apps. For the wider platform, see iOS app security.

Further reading

Common questions

  • Can I stop someone modifying a copy of my iOS app?

    No, but your server can refuse that copy's requests. Every mod must be re-signed, which changes the app's identity: a different Team ID, a provisioning profile that App Store builds do not have, and keys that do not match your App ID. App Attest lets the server tell your genuine app apart.

  • Why does App Attest flag a re-signed copy?

    Because the attestation includes a hash of your App ID, which is your Team ID plus bundle ID. A re-signed copy runs under a different Team ID, so its attestation fails your check, or it fails to obtain one at all. Requests without a valid assertion do not reach sensitive operations.

  • How can the app read its own Team ID at runtime?

    Add a keychain item and query its kSecAttrAccessGroup attribute; the value starts with the Team ID. A genuine App Store install shows your Team ID, while a re-signed copy usually shows another. A mod author can patch in-app checks, so protect the code that runs them and never rely on them alone.

  • Why run the provisioning profile check only in App Store builds?

    Because development, ad hoc and enterprise builds of your own app contain embedded.mobileprovision. An App Store install has no embedded profile, while a re-signed copy usually carries one naming another team. Record your own legitimate signing changes so they are never mistaken for mods.

  • Are installs from EU alternative marketplaces re-signed mods?

    No. In the European Union, apps from alternative marketplaces and web distribution are still signed with the developer's own certificate and notarised by Apple. Expect legitimate installs from these channels if you use them and record them as approved. MarketplaceKit's AppDistributor reports which channel installed the app.

Verify your signed release boundary

Tell us your iOS framework, distribution channel and integrity requirement. Do not send binaries, certificates with private keys, provisioning secrets or production data.

Or request a technical demo