In-App Protection Shielder for Apple

In-App Protection Shielder for Apple is a command-line tool that adds protection to iOS applications after they are built. No source code changes are required, and the protection starts automatically when the application launches.

The Shielder processes application builds in .ipa and .app formats. The features are configured in an optional YAML configuration file. The output is a shielded .ipa file.

Overview of the Shielding Process

Overview of the shielding process

Supported Features

In-App Protection Shielder for Apple currently supports the following features:

Installation

In-App Protection Shielder for Apple is distributed in a private artifact repository as a package with the following components of the same version:
  • iap-shielder, the command-line tool,
  • IAPShielderRuntime.xcframework, the runtime SDK that the Shielder adds to the application,
  • iap-shielder-artifact-manifest.json, a metadata file required by the Shielder.

The manifest has to stay in the same folder as IAPShielderRuntime.xcframework.

In-App Protection Shielder for Apple requires macOS 13 or later.
Shielded applications support iOS 15 and later.

Personalized Configuration Required.
In order to use In-App Protection Shielder for Apple, you need a custom configuration and access credentials for the artifact repository. Contact your sales representative or technical consultant to obtain the necessary prerequisites.

To verify the installation, run:

iap-shielder --version

Usage

In-App Protection Shielder for Apple is a command-line tool. It requires:
  • an iOS application to be shielded (.ipa or .app),
  • the runtime SDK (IAPShielderRuntime.xcframework).

Optionally:

  • a configuration YAML file (without it, all features are enabled),
  • a signing configuration YAML file.

The output of the Shielder is a shielded .ipa file. If the output file already exists, it is overwritten. The input application is not modified. The Shielder exits with a non-zero exit code when processing fails.

The Shielder modifies the application, so the original signature is no longer valid. The shielded application has to be signed, either by the Shielder or afterwards. See Signing.

Applications downloaded from the App Store are encrypted and cannot be shielded. Use the build exported from Xcode or your build system.

Running the Shielder

iap-shielder protect [OPTIONS] <input-application>

Adding --dry-run validates the configuration and prints the shielding plan without writing any output.

Example

iap-shielder protect \
  --config config.yml \
  --signing-config signing.yml \
  --output App-shielded.ipa \
  App.ipa

Shielding without signing, for signing afterwards:

iap-shielder protect \
  --config config.yml \
  --defer-signing \
  --output App-shielded.ipa \
  App.ipa

where:

  • App.ipa - input application,
  • config.yml - configuration file, including the path to the runtime SDK, see Configuration,
  • signing.yml - signing configuration file, see Signing,
  • App-shielded.ipa - shielded output application. It must be different from the input file.

App Store Privacy Manifest

The runtime SDK contains its own privacy manifest (PrivacyInfo.xcprivacy), which is added to the shielded application together with the runtime SDK. Your application’s privacy manifest does not need any changes.

The runtime SDK does not track users and does not collect any data. It declares the following required reason APIs:

API Category Reason
NSPrivacyAccessedAPICategorySystemBootTime 35F9.1
NSPrivacyAccessedAPICategoryFileTimestamp C617.1

Command Line Options

In-App Protection Shielder for Apple supports the following command-line options:

iap-shielder protect [OPTIONS] <input-application>

Options on the command line override the same values in the configuration files.

Required Options

Option Description
--output <path>, -o Output file with the shielded application. Must be different from the input file. Not required with --dry-run.
--runtime <path> Path to IAPShielderRuntime.xcframework, with iap-shielder-artifact-manifest.json in the same folder. Not required if set as runtime.artifact in the configuration file.

Optional Options

Option Description
--config <config.yml> Configuration file. See Configuration.
--signing-config <signing.yml> Signing configuration file. See Signing.
--defer-signing Shields the application without signing it. The output has to be signed before installation.
--expected-team-id <team-id> Apple Team ID the application is signed with. Required for Repackaging Detection with deferred signing.
--trusted-certificate-sha256 <hash> SHA-256 hash of a trusted signing certificate. Repeat for each certificate. Replaces the list from the configuration file.
--dry-run Validates the inputs and prints the shielding plan. Writes no output.
--version Prints the version.
-h, --help Prints help.

Signing Options

These options are used only when the Shielder signs the application. They are not allowed with --defer-signing.

Option Description
--signing-identity <identity> SHA-1 hash (preferred) or name of the signing certificate in the keychain. Required unless set in the signing configuration file.
--keychain <path> Keychain with the signing identity.
--profile <path> Provisioning profile for the main application.
--profile-for <bundle-id>=<path> Provisioning profile for one bundle ID, for example an app extension. Repeatable.
--profiles-directory <path> Folder with provisioning profiles, matched to the application and its extensions automatically.
--entitlements <path> Entitlements file for the main application.
--entitlements-for <bundle-id>=<path> Entitlements file for one bundle ID. Repeatable.
--remove-entitlement <bundle-id>:<key> Removes one entitlement. Repeatable.
--[no-]synthesize-identifier-entitlements For unsigned input without an entitlements file, sets only the identifier entitlements.
--[no-]require-explicit-app-id Rejects provisioning profiles with a wildcard App ID. Required for App Store distribution.

Configuration

In-App Protection Shielder for Apple reads an optional configuration file, set with --config. The configuration file uses the YAML data format. All features are enabled by default and terminate the application when they detect an issue.

General structure of the configuration:

schema_version: 1

runtime:
  artifact: <path>

defer_signing: true | false
expected_team_id: "<Team ID>"
trusted_certificate_sha256:
  - "<SHA-256 hash>"

rasp:
  <feature>:
    enabled: true | false
    response:
      action: terminate | no_action
      exit_url: <HTTPS URL>

Rules:

  • schema_version: 1 is required.
  • Unknown keys are rejected.
  • Booleans are lowercase true or false.
  • Hashes and Team IDs should be quoted.
  • Paths are relative to the configuration file.

General Options

Option Description
schema_version Required. Must be 1.
runtime.artifact Path to IAPShielderRuntime.xcframework. Overridden by --runtime.
defer_signing true shields the application without signing it. Defaults to false. See Signing.
expected_team_id Apple Team ID the application is signed with. Required for repackaging detection with deferred signing. See Repackaging Detection.
trusted_certificate_sha256 SHA-256 hashes of signing certificates used outside the App Store and TestFlight. See Repackaging Detection.

RASP Options

Option Description
rasp.<feature>.enabled Turns the feature on or off. Defaults to true.
rasp.<feature>.response.action terminate (default) or no_action. See Recommended Responses.
rasp.<feature>.response.exit_url HTTPS URL opened when the application is terminated. Only with terminate.

RASP Features

Feature Description
   
jailbreak Jailbreak Detection
debugger Debugger Protection
hooking Hooking Detection
repackaging Repackaging Detection
binary_integrity Binary Integrity Verification
injection Injection Detection

Complete Example

schema_version: 1

runtime:
  artifact: IAPShielderRuntime.xcframework

expected_team_id: "ABCDE12345"
trusted_certificate_sha256:
  - "<SHA-256 of the signing certificate>"

rasp:
  jailbreak:
    response:
      action: terminate
      exit_url: https://example.com/security/jailbreak
  debugger:
    response:
      action: no_action # for example, internal builds that need debugging

Signing

In-App Protection Shielder for Apple modifies the application, so the application has to be signed after shielding. The Shielder can sign the application itself, or the application can be signed afterwards by the owner of the signing certificates.

Signing by the Shielder

The Shielder signs the application, its extensions, and the runtime SDK. The following are required:

  • a signing identity in an unlocked keychain,
  • a provisioning profile for the main application and for each app extension, from the same team as the signing identity.

Entitlements are taken from the original signature and can be adjusted with the entitlements options.

The signing inputs are set with the signing options or in a signing configuration file (--signing-config). Example:

schema_version: 1

signing:
  identity: "<SHA-1 of the signing certificate>"
  profiles:
    main: profiles/App.mobileprovision
    by_bundle_id:
      com.example.app.share: profiles/Share.mobileprovision
  require_explicit_app_id: true
Option Command Line Option
signing.identity --signing-identity
signing.keychain --keychain
signing.profiles.main --profile
signing.profiles.by_bundle_id --profile-for
signing.profiles.directory --profiles-directory
signing.entitlements.main --entitlements
signing.entitlements.by_bundle_id --entitlements-for
signing.entitlements.remove --remove-entitlement
signing.synthesize_identifier_entitlements --[no-]synthesize-identifier-entitlements
signing.require_explicit_app_id --[no-]require-explicit-app-id

The signing identities and their SHA-1 hashes are listed by:

security find-identity -v -p codesigning

Signing After Shielding

With --defer-signing, the Shielder keeps the existing signatures and profiles. The input application has to be signed, and the shielded application has to be signed again before installation.

All components have to be signed with certificates of the same team, from the innermost to the outermost:

  1. frameworks and libraries in Frameworks/, including IAPShielderRuntime.framework, without entitlements,
  2. app extensions in PlugIns/ and other nested bundles, such as App Clips or watch apps, each with its own provisioning profile,
  3. the main application, with its provisioning profile.

App extensions, nested bundles and the main application keep the entitlements of the original signature, adjusted to their provisioning profiles. Each provisioning profile has to include the signing certificate.

RASP Feature Overview

RASP (runtime application self-protection) features protect the application against several attack vectors.

Currently, In-App Protection Shielder for Apple covers the following problems:

The protection starts automatically when the application launches and also covers its app extensions.

Configuration

RASP features are configured in the rasp section of the configuration file. Each feature is enabled by default and can be turned off with enabled: false. When a feature detects an issue, it responds with one of the following actions:

  • terminate (default): the application is terminated. If exit_url is set, the URL is opened in the browser first.
  • no_action: the application keeps running.
rasp:
  jailbreak:
    response:
      action: terminate
      exit_url: https://example.com/security/jailbreak

The exit URL is stored in the application and can be read by anyone. Do not put access tokens, user identifiers, or other secrets in it.

In general, the following is recommended:

  • Keep the default terminate response for all features in release builds.
  • Open an exit URL with an explanation when a jailbroken device is detected.
  • Use no_action for debugger protection only in internal builds that need debugging.
  • Test the shielded application with all integrated third-party SDKs before release.

Jailbreak Detection

A jailbroken device has reduced system security. Applications on such a device are far easier to inspect and modify, and their protections are easier to bypass. In-App Protection Shielder for Apple is able to detect that the application runs on a jailbroken device and can be configured to terminate the application in that case.

Configuration

rasp:
  jailbreak:
    enabled: true
    response:
      action: terminate
      exit_url: https://example.com/security/jailbreak

Jailbreak detection is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

Debugger Protection

An attached debugger allows reading and changing the application’s memory and execution. Attaching a debugger should only be possible during development and should never happen to a production application. In-App Protection Shielder for Apple is able to detect and prevent debugger attachment and can be configured to terminate the application in that case.

Configuration

rasp:
  debugger:
    enabled: true
    response:
      action: terminate

Debugger protection is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

See Recommended Responses for builds that need debugging.

Hooking Detection

Hooking changes the behavior of application or system functions while the application runs, typically with dynamic instrumentation tools. It is used to bypass security checks, change application logic, or read sensitive data. In-App Protection Shielder for Apple is able to detect hooking and instrumentation tools and can be configured to terminate the application in that case.

Configuration

rasp:
  hooking:
    enabled: true
    response:
      action: terminate

Hooking detection is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

Repackaging Detection

Repackaging detection is a security feature that detects that the application was modified and signed again with a different signing certificate or by a different team. In-App Protection Shielder for Apple is able to detect that the application has been repackaged and can be configured to terminate the application in that case.

Configuration

expected_team_id: "ABCDE12345"
trusted_certificate_sha256:
  - "<SHA-256 of a signing certificate>"

rasp:
  repackaging:
    enabled: true
    response:
      action: terminate

Repackaging detection is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

Team ID

expected_team_id is the Apple Team ID the application is signed with. It is optional when the Shielder signs the application and, if set, must match the selected provisioning profiles. With deferred signing, expected_team_id is required for repackaging detection, and the final signature must use this Team ID.

The Team ID of a signed application can be read with:

codesign -dv App.app 2>&1 | grep TeamIdentifier

Trusted Certificates

trusted_certificate_sha256 lists the certificates the application is signed with outside the App Store and TestFlight, for example a Development certificate for development builds or a Distribution certificate for Ad Hoc and Enterprise builds. Builds signed by Apple for the App Store and TestFlight do not need to be listed.

The hash of a certificate can be computed from the keychain:

security find-certificate -c "Apple Development: Jane Doe" -Z | grep SHA-256

Or from a .cer file exported from Keychain Access:

shasum -a 256 certificate.cer

When the Shielder signs the application with an identity given by its SHA-1 hash and the list is not empty, the signing certificate is added to the list automatically.

An application signed with a certificate that is not listed is detected as repackaged.

Binary Integrity Verification

Binary integrity verification detects that the executable code of the application or of the runtime SDK was modified after shielding, for example to remove security checks. In-App Protection Shielder for Apple is able to detect modified code and can be configured to terminate the application in that case.

Configuration

rasp:
  binary_integrity:
    enabled: true
    response:
      action: terminate

Binary integrity verification is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

Injection Detection

Code injection loads foreign libraries into the application process. Injected code runs with the same access as the application and is a common way to inspect or change application behavior. In-App Protection Shielder for Apple is able to detect code injected into the application process and can be configured to terminate the application in that case.

Configuration

rasp:
  injection:
    enabled: true
    response:
      action: terminate

Injection detection is enabled by default and defaults to terminate. The available responses are described in RASP Feature Overview.

Release Notes

Current Release

Release 1.0.0

  • Initial release
  • Add processing of .ipa and .app files
  • Add Runtime Protection: jailbreak detection, debugger protection, hooking detection, repackaging detection, binary integrity verification, and injection detection
  • Add signing of the shielded application, or deferred signing for signing afterwards
Generated on Oct 29, 2026 (16:04)