diff --git a/best-practices/MASTG-BEST-0032.md b/best-practices/MASTG-BEST-0032.md
new file mode 100644
index 00000000000..9833e0d9f60
--- /dev/null
+++ b/best-practices/MASTG-BEST-0032.md
@@ -0,0 +1,54 @@
+---
+title: Implement Certificate Pinning on iOS
+alias: ios-implement-certificate-pinning
+id: MASTG-BEST-0032
+platform: ios
+knowledge: [MASTG-KNOW-0072]
+---
+
+## Overview
+
+Certificate pinning lets an iOS app reject TLS connections to servers that don't present a specific expected certificate or public key, even if the server's certificate is signed by a CA trusted by the OS. This protects against MITM attacks by rogue or compromised certificate authorities.
+
+## Recommendation
+
+Use Apple's built-in [Identity Pinning via `NSPinnedDomains`](https://developer.apple.com/news/?id=g9ejcf8y) in `Info.plist` as the primary pinning mechanism. This is the simplest and most maintainable approach, as it requires no code changes and is automatically enforced by the system for all connections made through the URL Loading System.
+
+```xml
+NSAppTransportSecurity
+
+ NSPinnedDomains
+
+ example.com
+
+ NSIncludesSubdomains
+
+ NSPinnedCAIdentities
+
+
+ SPKI-SHA256-BASE64
+ +[BASE64-ENCODED SHA-256 HASH OF SUBJECT PUBLIC KEY INFO]
+
+
+
+
+
+```
+
+If you need more control, implement pinning in the [`URLSessionDelegate`](https://developer.apple.com/documentation/foundation/urlsessiondelegate) method [`urlSession(_:didReceive:completionHandler:)`](https://developer.apple.com/documentation/foundation/urlsessiondelegate/1409308-urlsession) and perform [manual server trust authentication](https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication).
+
+## Caveats and Considerations
+
+- **Pin to a CA public key, not a leaf certificate** when possible. Leaf certificates rotate frequently; CA public keys are more stable, avoiding forced app updates on every certificate renewal.
+- **Always include a backup pin** (a second CA or leaf key) to ensure connectivity if the primary certificate is replaced unexpectedly. Without a backup, a certificate rotation could render the app unable to connect.
+- **Manage pin rotation carefully.** Unlike Android's Network Security Configuration, `NSPinnedDomains` doesn't support expiration dates. Plan certificate rotation before pins become stale.
+- **Pinning doesn't replace proper TLS configuration.** Ensure the server is using strong cipher suites, up-to-date TLS versions, and valid certificates from trusted CAs.
+- **Pinning can be bypassed** on jailbroken devices or via tools such as [SSL Kill Switch 2](https://github.com/nabla-c0d3/ssl-kill-switch2), and by reverse-engineering and repackaging the app. Complement pinning with other controls such as jailbreak detection and app integrity checks for high-risk scenarios.
+- **Cross-platform and third-party frameworks** may use their own network stacks that bypass ATS and `NSPinnedDomains` entirely. Verify that pinning is enforced at the framework level (for example, Dart's `HttpClient` for Flutter).
+
+## References
+
+- Apple Developer Documentation: [Identity Pinning: How to configure server certificates for your app](https://developer.apple.com/news/?id=g9ejcf8y)
+- Apple Developer Documentation: [NSPinnedDomains](https://developer.apple.com/documentation/bundleresources/information-property-list/nsapptransportsecurity/nspinneddomains)
+- Apple Developer Documentation: [Performing Manual Server Trust Authentication](https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication)
+- Apple Developer Documentation: [Preventing Insecure Network Connections](https://developer.apple.com/documentation/security/preventing_insecure_network_connections)
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info.plist b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info.plist
new file mode 100644
index 00000000000..d0d86e89f06
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ NSAppTransportSecurity
+
+
+
+
+
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info_reversed.plist b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info_reversed.plist
new file mode 100644
index 00000000000..639de3144df
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/Info_reversed.plist
@@ -0,0 +1,86 @@
+
+
+
+
+ BuildMachineOSBuild
+ 25C56
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ MASTestApp
+ CFBundleIdentifier
+ org.owasp.mastestapp.MASTestApp-iOS
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ MASTestApp
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ CFBundleVersion
+ 1
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 23C53
+ DTPlatformName
+ iphoneos
+ DTPlatformVersion
+ 26.2
+ DTSDKBuild
+ 23C53
+ DTSDKName
+ iphoneos26.2
+ DTXcode
+ 2620
+ DTXcodeBuild
+ 17C52
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 17.1.1
+ NSAppTransportSecurity
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+
+ UIApplicationSupportsIndirectInputEvents
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UILaunchScreen
+
+ UILaunchScreen
+
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~iphone
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MASTG-DEMO-0x01.md b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MASTG-DEMO-0x01.md
new file mode 100644
index 00000000000..a6066a68bf3
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MASTG-DEMO-0x01.md
@@ -0,0 +1,32 @@
+---
+platform: ios
+title: Missing Certificate Pinning in ATS
+code: [swift, xml]
+id: MASTG-DEMO-0x01
+test: MASTG-TEST-0x01
+kind: fail
+---
+
+## Sample
+
+The sample below shows an app that makes HTTPS connections to `api.example.com` via `URLSession`. While the app uses HTTPS, the `Info.plist` file contains an `NSAppTransportSecurity` section with no `NSPinnedDomains` key, meaning no certificate pinning is configured via ATS:
+
+{{ MastgTest.swift # Info.plist }}
+
+## Steps
+
+1. Extract the app (@MASTG-TECH-0058) and locate the `Info.plist` file inside the app bundle (which we'll name `Info_reversed.plist`).
+2. Convert the `Info.plist` to a JSON format (@MASTG-TECH-0138).
+3. Search for `NSPinnedDomains` in the ATS configuration.
+
+{{ run.sh }}
+
+## Observation
+
+The output is empty, indicating that `NSPinnedDomains` is not present in the `NSAppTransportSecurity` section of the `Info.plist`:
+
+{{ output.txt }}
+
+## Evaluation
+
+The test fails because the `Info.plist` does not contain a `NSPinnedDomains` key inside `NSAppTransportSecurity`. As a result, the app doesn't enforce certificate pinning via ATS and relies entirely on the system CA trust store.
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MastgTest.swift b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MastgTest.swift
new file mode 100644
index 00000000000..013489d68be
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/MastgTest.swift
@@ -0,0 +1,21 @@
+import Foundation
+
+struct MastgTest {
+ // SUMMARY: This sample demonstrates missing certificate pinning configuration in ATS.
+ // The app makes HTTPS connections but the Info.plist does not configure NSPinnedDomains,
+ // leaving it vulnerable to MITM attacks via rogue or compromised certificate authorities.
+
+ static func mastgTest(completion: @escaping (String) -> Void) {
+ // FAIL: [MASTG-TEST-0x01] No certificate pinning configured via NSPinnedDomains in Info.plist.
+ // The app relies solely on the system CA trust store.
+ let url = URL(string: "https://api.example.com/data")!
+ let task = URLSession.shared.dataTask(with: url) { _, response, error in
+ if let error = error {
+ completion("Request failed: \(error.localizedDescription)")
+ } else if let httpResponse = response as? HTTPURLResponse {
+ completion("Request to api.example.com returned status: \(httpResponse.statusCode)")
+ }
+ }
+ task.resume()
+ }
+}
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/output.txt b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/output.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/run.sh b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/run.sh
new file mode 100755
index 00000000000..1d33e82e385
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x01/run.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+plutil -convert json -o Info_reversed.json Info_reversed.plist
+
+# pretty print json
+jq . Info_reversed.json > Info_reversed.json.tmp && mv Info_reversed.json.tmp Info_reversed.json
+
+gron -m Info_reversed.json | grep 'NSPinnedDomains' > output.txt
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info.plist b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info.plist
new file mode 100644
index 00000000000..ce4a266018b
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info.plist
@@ -0,0 +1,28 @@
+
+
+
+
+ NSAppTransportSecurity
+
+ TSKConfiguration
+
+ TSKSwizzleNetworkDelegates
+
+ TSKPinnedDomains
+
+ api.example.com
+
+ TSKIncludeSubdomains
+
+ TSKPublicKeyHashes
+
+ HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=
+ 0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WkTpymPxdc=
+
+ TSKExpirationDate
+ 2020-01-01
+
+
+
+
+
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info_reversed.plist b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info_reversed.plist
new file mode 100644
index 00000000000..21e874b2e49
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/Info_reversed.plist
@@ -0,0 +1,106 @@
+
+
+
+
+ BuildMachineOSBuild
+ 25C56
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ MASTestApp
+ CFBundleIdentifier
+ org.owasp.mastestapp.MASTestApp-iOS
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ MASTestApp
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ CFBundleVersion
+ 1
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 23C53
+ DTPlatformName
+ iphoneos
+ DTPlatformVersion
+ 26.2
+ DTSDKBuild
+ 23C53
+ DTSDKName
+ iphoneos26.2
+ DTXcode
+ 2620
+ DTXcodeBuild
+ 17C52
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 17.1.1
+ NSAppTransportSecurity
+
+ TSKConfiguration
+
+ TSKPinnedDomains
+
+ api.example.com
+
+ TSKExpirationDate
+ 2020-01-01
+ TSKIncludeSubdomains
+
+ TSKPublicKeyHashes
+
+ HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=
+ 0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WkTpymPxdc=
+
+
+
+ TSKSwizzleNetworkDelegates
+
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+
+ UIApplicationSupportsIndirectInputEvents
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UILaunchScreen
+
+ UILaunchScreen
+
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~iphone
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MASTG-DEMO-0x02.md b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MASTG-DEMO-0x02.md
new file mode 100644
index 00000000000..d04774cc18a
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MASTG-DEMO-0x02.md
@@ -0,0 +1,32 @@
+---
+platform: ios
+title: Expired Certificate Pins in ATS
+code: [swift, xml]
+id: MASTG-DEMO-0x02
+test: MASTG-TEST-0x02
+kind: fail
+---
+
+## Sample
+
+The sample below shows an app that makes HTTPS connections to `api.example.com`. It uses [TrustKit](https://github.com/datatheorem/TrustKit) for certificate pinning, configured via the `TSKConfiguration` key in `Info.plist`. However, the `TSKExpirationDate` for the pinned domain is set to `2020-01-01`, which is in the past. After this date, TrustKit stops enforcing certificate pinning for the domain and falls back to the system CA trust store:
+
+{{ MastgTest.swift # Info.plist }}
+
+## Steps
+
+1. Extract the app (@MASTG-TECH-0058) and locate the `Info.plist` file inside the app bundle (which we'll name `Info_reversed.plist`).
+2. Convert the `Info.plist` to a JSON format (@MASTG-TECH-0138).
+3. Search for `TSKExpirationDate` values in the TrustKit configuration.
+
+{{ run.sh }}
+
+## Observation
+
+The output shows the `TSKExpirationDate` value for the pinned domain:
+
+{{ output.txt }}
+
+## Evaluation
+
+The test fails because the `TSKExpirationDate` for `api.example.com` is `2020-01-01`, which is in the past. TrustKit has already stopped enforcing certificate pinning for this domain.
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MastgTest.swift b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MastgTest.swift
new file mode 100644
index 00000000000..04165388eb1
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/MastgTest.swift
@@ -0,0 +1,21 @@
+import Foundation
+
+struct MastgTest {
+ // SUMMARY: This sample demonstrates expired certificate pinning configuration using TrustKit.
+ // TrustKit is configured via Info.plist with a TSKExpirationDate set in the past.
+ // After the expiration date, TrustKit stops enforcing certificate pinning for the affected domains.
+
+ static func mastgTest(completion: @escaping (String) -> Void) {
+ // FAIL: [MASTG-TEST-0x02] The TrustKit pin configuration for api.example.com has an
+ // expired TSKExpirationDate (2020-01-01). TrustKit will no longer enforce pinning.
+ let url = URL(string: "https://api.example.com/data")!
+ let task = URLSession.shared.dataTask(with: url) { _, response, error in
+ if let error = error {
+ completion("Request failed: \(error.localizedDescription)")
+ } else if let httpResponse = response as? HTTPURLResponse {
+ completion("Request to api.example.com returned status: \(httpResponse.statusCode)")
+ }
+ }
+ task.resume()
+ }
+}
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/output.txt b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/output.txt
new file mode 100644
index 00000000000..73433daf120
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/output.txt
@@ -0,0 +1 @@
+json.TSKConfiguration.TSKPinnedDomains["api.example.com"].TSKExpirationDate = "2020-01-01";
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/run.sh b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/run.sh
new file mode 100755
index 00000000000..6671d3df08a
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x02/run.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+plutil -convert json -o Info_reversed.json Info_reversed.plist
+
+# pretty print json
+jq . Info_reversed.json > Info_reversed.json.tmp && mv Info_reversed.json.tmp Info_reversed.json
+
+gron -m Info_reversed.json | grep 'TSKExpirationDate' > output.txt
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MASTG-DEMO-0x03.md b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MASTG-DEMO-0x03.md
new file mode 100644
index 00000000000..eeff52e2f3b
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MASTG-DEMO-0x03.md
@@ -0,0 +1,41 @@
+---
+platform: ios
+title: Runtime Use of Certificate Pinning APIs
+code: [swift]
+id: MASTG-DEMO-0x03
+test: MASTG-TEST-0x03
+kind: fail
+status: draft
+---
+
+## Sample
+
+The sample below shows an app that implements `URLSessionDelegate` to perform manual server trust evaluation. However, the implementation is flawed: it calls `completionHandler(.useCredential, credential)` unconditionally without comparing the server's certificate against any expected pinned value:
+
+{{ MastgTest.swift }}
+
+## Steps
+
+1. Ensure the device is prepared for dynamic analysis (see @MASTG-TECH-0090).
+2. Use @MASTG-TECH-0064 to attempt to bypass certificate pinning and identify which pinning APIs are being hooked. Run the following @MASTG-TOOL-0038 command:
+
+ ```bash
+ ios sslpinning disable
+ ```
+
+3. Alternatively, use @MASTG-TECH-0086 with @MASTG-TOOL-0031 to trace `URLSessionDelegate` method calls. For example:
+
+ ```bash
+ frida-trace -U -f org.owasp.mastestapp \
+ -m '-[* URLSession:didReceiveChallenge:completionHandler:]' \
+ -m '-[* webView:didReceiveAuthenticationChallenge:completionHandler:]' \
+ > output.txt
+ ```
+
+## Observation
+
+The output should contain a list of certificate pinning-related delegate method calls observed at runtime, including the class and method names.
+
+## Evaluation
+
+The test fails in this case because the `urlSession(_:didReceive:completionHandler:)` delegate method is called but the implementation accepts any server credential unconditionally without verifying the server certificate against a pinned value.
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MastgTest.swift b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MastgTest.swift
new file mode 100644
index 00000000000..fe97fb600fd
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x03/MastgTest.swift
@@ -0,0 +1,39 @@
+import Foundation
+
+struct MastgTest: URLSessionDelegate {
+ // SUMMARY: This sample demonstrates certificate pinning via URLSessionDelegate.
+ // The URLSession is initialized with this delegate to perform manual server trust evaluation
+ // during each TLS handshake.
+
+ // FAIL: [MASTG-TEST-0x03] The pinning implementation accepts any server credential
+ // unconditionally, without comparing the certificate against an expected value.
+ // This means the "pinning" check is always bypassed.
+ func urlSession(
+ _ session: URLSession,
+ didReceive challenge: URLAuthenticationChallenge,
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
+ ) {
+ guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
+ let serverTrust = challenge.protectionSpace.serverTrust else {
+ completionHandler(.performDefaultHandling, nil)
+ return
+ }
+ // Insecure: accepts any server certificate without validating against a pinned value
+ let credential = URLCredential(trust: serverTrust)
+ completionHandler(.useCredential, credential)
+ }
+
+ static func mastgTest(completion: @escaping (String) -> Void) {
+ let delegate = MastgTest()
+ let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
+ let url = URL(string: "https://api.example.com/data")!
+ let task = session.dataTask(with: url) { _, response, error in
+ if let error = error {
+ completion("Request failed: \(error.localizedDescription)")
+ } else if let httpResponse = response as? HTTPURLResponse {
+ completion("Request to api.example.com returned status: \(httpResponse.statusCode)")
+ }
+ }
+ task.resume()
+ }
+}
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MASTG-DEMO-0x04.md b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MASTG-DEMO-0x04.md
new file mode 100644
index 00000000000..fd4d172fdae
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MASTG-DEMO-0x04.md
@@ -0,0 +1,30 @@
+---
+platform: ios
+title: Missing Certificate Pinning in Network Traffic
+code: [swift]
+id: MASTG-DEMO-0x04
+test: MASTG-TEST-0x04
+kind: fail
+status: draft
+---
+
+## Sample
+
+The sample below shows an app that makes HTTPS connections via `URLSession` with no certificate pinning configured. It doesn't implement `NSPinnedDomains` in `Info.plist` and doesn't use a custom `URLSessionDelegate` for server trust evaluation. As a result, any certificate issued by a CA trusted by the device (including a proxy CA certificate) is accepted:
+
+{{ MastgTest.swift }}
+
+## Steps
+
+1. Set up an interception proxy on the testing device (@MASTG-TECH-0063).
+2. Install and run the app on the device.
+3. Trigger network communication (for example, by interacting with the app's UI).
+4. Observe whether the proxy successfully intercepts HTTPS traffic from the app.
+
+## Observation
+
+The output should contain a list of HTTPS domains for which the interception was successful.
+
+## Evaluation
+
+The test fails because the proxy successfully intercepts HTTPS traffic to `api.example.com`. This confirms that the app doesn't enforce certificate pinning: it accepts a certificate issued by the proxy's CA, which is trusted by the device but not the app's intended server.
diff --git a/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MastgTest.swift b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MastgTest.swift
new file mode 100644
index 00000000000..5d32e884262
--- /dev/null
+++ b/demos/ios/MASVS-NETWORK/MASTG-DEMO-0x04/MastgTest.swift
@@ -0,0 +1,21 @@
+import Foundation
+
+struct MastgTest {
+ // SUMMARY: This sample demonstrates an app that does not enforce certificate pinning.
+ // The app makes HTTPS connections via URLSession with no NSPinnedDomains in Info.plist
+ // and no custom URLSessionDelegate trust evaluation. A MITM attack using a proxy
+ // CA certificate trusted by the device will successfully intercept traffic.
+
+ static func mastgTest(completion: @escaping (String) -> Void) {
+ // FAIL: [MASTG-TEST-0x04] No certificate pinning enforced. MITM interception succeeds.
+ let url = URL(string: "https://api.example.com/data")!
+ let task = URLSession.shared.dataTask(with: url) { _, response, error in
+ if let error = error {
+ completion("Request failed: \(error.localizedDescription)")
+ } else if let httpResponse = response as? HTTPURLResponse {
+ completion("Request to api.example.com returned status: \(httpResponse.statusCode)")
+ }
+ }
+ task.resume()
+ }
+}
diff --git a/knowledge/ios/MASVS-NETWORK/MASTG-KNOW-0072.md b/knowledge/ios/MASVS-NETWORK/MASTG-KNOW-0072.md
index b7c5c91ec2d..a363efe2694 100644
--- a/knowledge/ios/MASVS-NETWORK/MASTG-KNOW-0072.md
+++ b/knowledge/ios/MASVS-NETWORK/MASTG-KNOW-0072.md
@@ -20,3 +20,94 @@ References:
- [Preventing Insecure Network Connections](https://developer.apple.com/documentation/security/preventing_insecure_network_connections)
- [Performing Manual Server Trust Authentication](https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication)
- [Certificate, Key, and Trust Services](https://developer.apple.com/documentation/security/certificate_key_and_trust_services)
+
+## Certificate Pinning
+
+[Certificate pinning](../../../Document/0x04f-Testing-Network-Communication.md#restricting-trust-identity-pinning) allows an iOS app to reject certificates that don't match a specific expected identity, guarding against Machine-in-the-Middle (MITM) attacks even when an attacker controls a CA that is trusted by the system.
+
+While effective when implemented correctly, insecure implementations can potentially enable attackers to read and modify all communication. For more general details on pinning, refer to @MASWE-0047.
+
+**Important Considerations:**
+
+Certificate pinning is a **hardening practice**, but it's not foolproof. There are multiple ways an attacker can bypass it, such as:
+
+- **Modifying the certificate validation logic** in the app's `URLSessionDelegate` or custom `SecTrust` evaluation.
+- **Replacing pinned certificates** stored in the app bundle.
+- **Altering or removing pins** in the `Info.plist` `NSPinnedDomains` configuration.
+
+Any such modification **invalidates the app's code signature**, requiring the attacker to **re-sign the app**. To mitigate these risks, additional protections such as integrity checks and runtime verification may be required.
+
+### Pinning via App Transport Security (ATS)
+
+Apple's [Identity Pinning](https://developer.apple.com/news/?id=g9ejcf8y) feature lets you declare expected CA public key hashes directly in the `Info.plist` file under [`NSPinnedDomains`](https://developer.apple.com/documentation/bundleresources/information-property-list/nsapptransportsecurity/nspinneddomains). This is the recommended approach because it requires no code changes and is enforced by the system for connections made through the URL Loading System.
+
+```xml
+NSAppTransportSecurity
+
+ NSPinnedDomains
+
+ example.com
+
+ NSIncludesSubdomains
+
+ NSPinnedCAIdentities
+
+
+ SPKI-SHA256-BASE64
+ +[BASE64-ENCODED SHA-256 HASH OF SUBJECT PUBLIC KEY INFO]
+
+
+
+
+
+```
+
+The `NSPinnedCAIdentities` key pins an intermediate or root CA's public key. You can alternatively use `NSPinnedLeafIdentities` to pin the leaf (server) certificate's public key, though pinning to a CA is more resilient to certificate renewals.
+
+**Important Considerations:**
+
+- **Backup Pins:** Apple recommends including at least one backup pin (a different CA or leaf key) to maintain connectivity if the primary certificate changes unexpectedly.
+- **No Expiration Support:** Unlike the Android Network Security Configuration, `NSPinnedDomains` doesn't support expiration dates. Developers must manage certificate rotation manually.
+- **Scope:** ATS pinning applies only to connections made via the URL Loading System (for example, `URLSession`). It doesn't apply to `Network` framework, `CFNetwork`, or BSD socket connections.
+
+### Pinning via Manual Server Trust Evaluation
+
+Apps can implement pinning in code by implementing the [`URLSessionDelegate`](https://developer.apple.com/documentation/foundation/urlsessiondelegate) method [`urlSession(_:didReceive:completionHandler:)`](https://developer.apple.com/documentation/foundation/urlsessiondelegate/1409308-urlsession) to perform [manual server trust authentication](https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication). This approach gives full programmatic control over which credentials to accept.
+
+A typical implementation extracts the server's `SecTrust` from the authentication challenge, then compares the certificate's or public key's fingerprint against a hardcoded expected value.
+
+**Important Note:** Manual trust evaluation is **error-prone**. Common mistakes include:
+
+- Calling `completionHandler(.useCredential, ...)` unconditionally without verifying the certificate.
+- Forgetting to call `completionHandler(.cancelAuthenticationChallenge, nil)` on mismatch, leaving the connection open.
+- Using certificate-level pinning instead of public key pinning, which requires an app update on every certificate renewal.
+
+### Pinning via Third-party Libraries
+
+Several third-party libraries simplify certificate pinning on iOS:
+
+- **[TrustKit](https://github.com/datatheorem/TrustKit)**: Configure public key hashes in `Info.plist` or in code. TrustKit swizzles `NSURLSession` and `NSURLConnection` delegates to enforce pinning transparently.
+- **[Alamofire](https://github.com/Alamofire/Alamofire)**: Define a `ServerTrustManager` with a `PinnedCertificatesTrustEvaluator` or `PublicKeysTrustEvaluator` per domain. See the [Alamofire Security documentation](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security) for details.
+- **[AFNetworking](https://github.com/AFNetworking/AFNetworking)**: Configure pinning via `AFSecurityPolicy` with `AFSSLPinningModeCertificate` or `AFSSLPinningModePublicKey`.
+
+These libraries typically provide higher-level abstractions over the `URLSession` delegate mechanism, but they may not cover all network traffic in the app (for example, traffic from native code or third-party SDKs with their own network stacks).
+
+### Pinning in WebViews
+
+`WKWebView` doesn't expose a direct API for certificate pinning equivalent to `URLSession`'s delegate. However, you can intercept navigation requests using [`WKNavigationDelegate`](https://developer.apple.com/documentation/webkit/wknavigationdelegate) and the method [`webView(_:didReceive:completionHandler:)`](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview) to perform custom trust evaluation, similar to the `URLSession` delegate approach.
+
+Note that this method only covers top-level navigation challenges. Sub-resource loads (images, scripts, XHR) inside a `WKWebView` aren't covered, so this approach provides incomplete pinning coverage for web content.
+
+### Pinning in Native Code
+
+Pinning can also be implemented in native (C/C++) code using the Security framework's lower-level [`SecTrust`](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/trust) APIs or via the `Network` framework. Embedding certificate or public key verification within compiled native libraries increases the difficulty of bypassing or modifying pinning via typical IPA reverse engineering, but it also makes maintenance and debugging more complex.
+
+### Pinning in Cross-Platform Frameworks
+
+Cross-platform frameworks (Flutter, React Native, Cordova, Xamarin) often require special considerations for certificate pinning, because they may use their own network stack instead of the platform's URL Loading System:
+
+- **Flutter**: Uses Dart's `HttpClient` backed by BoringSSL, bypassing ATS entirely. Certificate pinning must be implemented at the Dart level using `SecurityContext` or a custom `badCertificateCallback`, or via a native plugin.
+- **React Native**: Network requests go through the native iOS networking stack by default, so ATS and `URLSession`-based pinning can apply. Third-party plugins (for example, `react-native-ssl-pinning`) also exist.
+- **Cordova / Ionic**: Requests from JavaScript are typically made through a `WKWebView`. See the WebViews section above, and also consider Cordova plugins that add native pinning support.
+
+Understanding how a framework handles networking is crucial for ensuring that pinning is actually enforced.
diff --git a/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x01.md b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x01.md
new file mode 100644
index 00000000000..e825096e74f
--- /dev/null
+++ b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x01.md
@@ -0,0 +1,36 @@
+---
+platform: ios
+title: Missing Certificate Pinning in ATS
+id: MASTG-TEST-0x01
+type: [static]
+weakness: MASWE-0047
+profiles: [L2]
+best-practices: [MASTG-BEST-0032]
+knowledge: [MASTG-KNOW-0072]
+---
+
+## Overview
+
+iOS apps can configure certificate pinning via App Transport Security (ATS) by declaring expected CA or leaf certificate public key hashes in the `Info.plist` file under the [`NSPinnedDomains`](https://developer.apple.com/documentation/bundleresources/information-property-list/nsapptransportsecurity/nspinneddomains) key. This is Apple's recommended declarative approach for enforcing certificate pinning for connections made through the URL Loading System (for example, `URLSession`).
+
+If an app doesn't configure `NSPinnedDomains`, it relies entirely on the system's default CA trust store, which means a MITM attacker with control over a trusted CA can intercept its traffic.
+
+This test checks whether the app configures `NSPinnedDomains` in its ATS settings.
+
+!!! warning Limitations
+ ATS pinning only applies to connections made via the URL Loading System (for example, `URLSession`). It doesn't cover connections made using lower-level APIs such as the `Network` framework or `CFNetwork`. Additionally, `NSPinnedDomains` doesn't cover all possible certificate pinning implementations; the app may use manual `URLSessionDelegate` trust evaluation, third-party libraries, or native-code pinning instead. This test focuses exclusively on the ATS-based approach.
+
+## Steps
+
+1. Extract the app (@MASTG-TECH-0058).
+2. Obtain the `Info.plist` file from the app bundle.
+3. Use @MASTG-TECH-0138 to convert the `Info.plist` to a readable format (if necessary).
+4. Examine the `NSAppTransportSecurity` dictionary for the presence of a `NSPinnedDomains` key.
+
+## Observation
+
+The output should contain the ATS configuration, if present, including whether `NSPinnedDomains` is defined with one or more pinned domains and their associated public key hashes.
+
+## Evaluation
+
+The test case fails if the app's `Info.plist` does not contain an `NSAppTransportSecurity` dictionary with a `NSPinnedDomains` key, or if `NSPinnedDomains` is defined but doesn't include entries for all relevant domains the app connects to.
diff --git a/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x02.md b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x02.md
new file mode 100644
index 00000000000..dfd11f1ec29
--- /dev/null
+++ b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x02.md
@@ -0,0 +1,36 @@
+---
+platform: ios
+title: Expired Certificate Pins in ATS
+id: MASTG-TEST-0x02
+type: [static]
+weakness: MASWE-0047
+profiles: [L2]
+best-practices: [MASTG-BEST-0032]
+knowledge: [MASTG-KNOW-0072]
+---
+
+## Overview
+
+iOS apps can configure certificate pinning via App Transport Security (ATS) using the [`NSPinnedDomains`](https://developer.apple.com/documentation/bundleresources/information-property-list/nsapptransportsecurity/nspinneddomains) key in `Info.plist`. Unlike Android's Network Security Configuration, ATS `NSPinnedDomains` doesn't support expiration dates for pins. However, apps that use third-party certificate pinning libraries (such as [TrustKit](https://github.com/datatheorem/TrustKit)) may configure pin expiration dates in `Info.plist` through the library's own configuration keys (for example, TrustKit's `kTSKExpirationDate`).
+
+If a pin expiration date is set and has passed, pinning enforcement is typically disabled by the library, causing the app to accept any certificate valid according to the system trust store. If developers assume pinning is still in effect after it has expired, the app may start trusting CAs it was never intended to trust.
+
+> Example: A financial app previously pinned to its own private CA, but after the expiration date passes, the library stops enforcing pinning and starts accepting certificates from any publicly trusted CA, increasing the risk of compromise if a CA is breached.
+
+The goal of this test is to check if any pin expiration date configured in `Info.plist` is in the past.
+
+## Steps
+
+1. Extract the app (@MASTG-TECH-0058).
+2. Obtain the `Info.plist` file from the app bundle.
+3. Use @MASTG-TECH-0138 to convert the `Info.plist` to a readable format (if necessary).
+4. Look for certificate pinning library configuration keys in `Info.plist` (for example, TrustKit's `TSKConfiguration` dictionary with `kTSKExpirationDate` values).
+5. Extract all expiration dates from the pinning configuration.
+
+## Observation
+
+The output should contain a list of expiration dates found for pinned certificates, alongside the domains they are associated with.
+
+## Evaluation
+
+The test case fails if any expiration date found is in the past.
diff --git a/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x03.md b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x03.md
new file mode 100644
index 00000000000..68c9c68f18a
--- /dev/null
+++ b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x03.md
@@ -0,0 +1,48 @@
+---
+platform: ios
+title: Runtime Use of Certificate Pinning APIs
+id: MASTG-TEST-0x03
+type: [dynamic]
+weakness: MASWE-0047
+profiles: [L2]
+best-practices: [MASTG-BEST-0032]
+knowledge: [MASTG-KNOW-0072]
+---
+
+## Overview
+
+iOS apps can implement certificate pinning using different APIs. At runtime, pinning is typically enforced via:
+
+- The [`URLSessionDelegate`](https://developer.apple.com/documentation/foundation/urlsessiondelegate) method [`urlSession(_:didReceive:completionHandler:)`](https://developer.apple.com/documentation/foundation/urlsessiondelegate/1409308-urlsession) for manual server trust evaluation.
+- Third-party libraries such as [TrustKit](https://github.com/datatheorem/TrustKit), [Alamofire](https://github.com/Alamofire/Alamofire), or [AFNetworking](https://github.com/AFNetworking/AFNetworking), which typically wrap `URLSession` delegate methods.
+- The `WKNavigationDelegate` method [`webView(_:didReceive:completionHandler:)`](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview) for `WKWebView`-based pinning.
+
+This test uses dynamic instrumentation to trace certificate pinning API calls at runtime, which helps to determine whether the app is actually invoking pinning logic during network communication and to identify the specific APIs used. This can be used to supplement static analysis, especially when the app uses obfuscation or dynamically loaded code.
+
+!!! note
+ A positive result (pinning APIs being called) doesn't confirm that pinning is correctly implemented. The implementation may still be flawed (for example, accepting any credential unconditionally). Use this test together with @MASTG-TEST-0x04 to verify that pinning is enforced end-to-end.
+
+## Steps
+
+1. Ensure the device is prepared for dynamic analysis (see @MASTG-TECH-0090).
+2. Use @MASTG-TECH-0064 to attempt to bypass certificate pinning and identify which pinning APIs are being hooked.
+3. Alternatively, use @MASTG-TECH-0086 to method-trace the relevant certificate pinning APIs, such as:
+ - `URLSessionDelegate` methods: `-[* URLSession:didReceiveChallenge:completionHandler:]`
+ - `SecTrustEvaluateWithError`
+ - `SecTrustEvaluate` (deprecated but still in use)
+ - `WKNavigationDelegate` methods: `-[* webView:didReceiveAuthenticationChallenge:completionHandler:]`
+
+## Observation
+
+The output should contain a list of certificate pinning API calls observed at runtime, including the methods invoked and the class names that implement them.
+
+## Evaluation
+
+The test case fails if no certificate pinning APIs are called during active network communication with the app's backend endpoints, indicating that the app doesn't implement runtime certificate pinning.
+
+Note that a missing API call could also indicate that:
+
+- The app uses ATS `NSPinnedDomains` (system-level pinning not visible via method tracing).
+- The app uses pinning implemented in native code, which requires additional analysis.
+
+In either case, complement this test with static analysis (@MASTG-TEST-0x01) and network interception (@MASTG-TEST-0x04) to get a complete picture.
diff --git a/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x04.md b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x04.md
new file mode 100644
index 00000000000..ecbc7787c6e
--- /dev/null
+++ b/tests-beta/ios/MASVS-NETWORK/MASTG-TEST-0x04.md
@@ -0,0 +1,34 @@
+---
+platform: network
+title: Missing Certificate Pinning in Network Traffic
+id: MASTG-TEST-0x04
+type: [network]
+weakness: MASWE-0047
+profiles: [L2]
+best-practices: [MASTG-BEST-0032]
+knowledge: [MASTG-KNOW-0072]
+---
+
+## Overview
+
+There are multiple ways an iOS app can implement certificate pinning, including via ATS `NSPinnedDomains`, manual `URLSessionDelegate` trust evaluation, third-party libraries, and native code. Since some implementations might be difficult to identify through static analysis, especially when obfuscation or dynamic code loading is involved, this test uses network interception techniques to determine whether certificate pinning is enforced at runtime.
+
+The goal of this test is to observe whether a MITM attack can intercept HTTPS traffic from the app. A successful MITM interception indicates that the app either doesn't use certificate pinning or implements it incorrectly.
+
+If the app properly implements certificate pinning, the MITM attack should fail because the app rejects certificates issued by an unauthorized CA, even if that CA is trusted by the system.
+
+_Testing Tip:_ While performing the MITM attack, monitor the system logs (see @MASTG-TECH-0060). If a certificate pinning check fails, log entries indicating a TLS handshake failure or a trust evaluation error may be visible.
+
+## Steps
+
+1. Set up an interception proxy (see @MASTG-TECH-0063).
+2. Install the application on a device connected to that proxy, and intercept the communication.
+3. Extract all domains for which the interception was successful.
+
+## Observation
+
+The output should contain a list of domains for which the interception was successful.
+
+## Evaluation
+
+The test case fails if any relevant domain was intercepted.
diff --git a/tests/ios/MASVS-NETWORK/MASTG-TEST-0068.md b/tests/ios/MASVS-NETWORK/MASTG-TEST-0068.md
index e6124686d78..9b058fb8563 100644
--- a/tests/ios/MASVS-NETWORK/MASTG-TEST-0068.md
+++ b/tests/ios/MASVS-NETWORK/MASTG-TEST-0068.md
@@ -8,6 +8,9 @@ title: Testing Custom Certificate Stores and Certificate Pinning
masvs_v1_levels:
- L2
profiles: [L2]
+status: deprecated
+covered_by: [MASTG-TEST-0x01, MASTG-TEST-0x02, MASTG-TEST-0x03, MASTG-TEST-0x04]
+deprecation_note: "New version available in MASTG V2"
---
## Overview