Lightweight iOS Security Detection Framework
Detect jailbreaks, debuggers, emulators, Frida, runtime hooks, SSL pinning bypasses, VPN/proxy usage and more.
| Category | Detection |
|---|---|
| 🔓 Jailbreak | Files, sandbox escape, fork capability, URL schemes, symlinks, environment variables |
| 🐞 Debugger | sysctl, ptrace, parent process, timing analysis, breakpoint instructions |
| 📱 Emulator | Hardware mismatch, simulator artifacts, DeviceCheck validation |
| 🧬 Reverse Engineering | Frida, Substrate, libhooker, runtime tampering |
| 🔒 App Integrity | Code signature validation, Team ID verification, CodeResources hash validation |
| 🪝 Hook Detection | Runtime function hook detection via ARM64 prologue inspection |
| 🔄 Swizzling Detection | Objective-C IMP redirection validation |
| 👾 Frida Detection | Libraries, symbols, process checks, multi-port scanning |
| 📺 Screen Recording | Active recording and mirroring detection |
| 📸 Screenshot Detection | Real-time screenshot notifications |
| 🌐 Pinning Bypass Detection | Detects bypass tools (SSLKillSwitch, ssl-proxy, etc.) and proxy configurations — not a substitute for implementing certificate/public-key pinning in your networking stack |
| 🔌 VPN / Proxy Detection | VPN interfaces and proxy configuration detection |
| 🔐 App Attest | Apple App Attest validation |
| 📦 Anti-Repackaging | Signing certificate verification |
| 🛡️ DSK Integrity | Runtime validation of DSK internals |
| ⏱️ Monitoring | Continuous background security monitoring |
import DeviceSecurityKit
DSK.shared
.configure(.production)
.onThreatDetected { threat in
print("Threat: \(threat.description)")
}
.start()- File → Add Package Dependencies
- Enter:
https://github.com/galahador/DeviceSecurityKit.git
- Select:
from: "0.28.0"
- Add Package
dependencies: [
.package(
url: "https://github.com/galahador/DeviceSecurityKit.git",
from: "0.28.0"
)
]DSK.shared
.configure(.production)
.start()DSK.shared
.onThreatDetected { threat in
print(threat.description)
}
.start()DSK.shared
.onStatusChange { status in
print(status)
}
.start()let result = DSK.shared.performCheck()
if result.isSecure {
print("Secure")
} else {
print(result.threats)
}DSK.shared
.onThreatDetected { threat in
switch threat.severity {
case .critical:
AuthManager.shared.clearTokens()
KeychainManager.shared.wipe()
Analytics.log(
"security_threat",
["type": threat.rawValue]
)
exit(0)
case .high:
showSecurityAlert()
default:
break
}
}
.start().configure(.default)
.configure(.production)
.configure(.jailbreakOnly)
.configure(.disabled)let config = DeviceSecurityConfiguration.default
.withJailbreakCheck(true)
.withDebuggerCheck(true)
.withEmulatorCheck(false)
.withReverseEngineeringCheck(true)
.withScreenRecordingCheck(true)
.withScreenshotDetection(true)
.withHookDetection(true)
.withPinningBypassDetection(true)
.withSwizzlingDetection(true)
.withFridaDetection(true)
.withAttestationCheck(true)
.withVPNProxyDetection(
true,
allowedBundleIDs: [
"com.example.corporate-vpn"
]
)
.withAppIntegrityCheck(
true,
expectedTeamID: "ABCDE12345"
)
.withAntiRepackagingCheck(
true,
expectedCertificateHash: "a1b2c3..."
)
DSK.shared
.configure(config)
.start()#if DEBUG
print(
RepackagingDetector.currentCertificateHash()
)
#endif.withAntiRepackagingCheck(
true,
expectedCertificateHash:
"your-hash-here"
).withVPNProxyDetection(
true,
allowedBundleIDs: [
"com.cisco.anyconnect",
"com.microsoft.intune.tunnel"
]
)DSK.shared
.monitoringInterval(30)
.start()Default:
60 seconds
DSK.shared
.countermeasure(
throttled: false
) { threat in
Analytics.log(
"dsk_threat",
["type": threat.rawValue]
)
}let cm = Countermeasure(
trigger: .threat(.fridaDetected),
throttled: true
) { _ in
exit(0)
}
DSK.shared.addCountermeasure(cm)DSK.shared.removeCountermeasure(cm)
DSK.shared.removeAllCountermeasures()
⚠️ Throttled countermeasures execute once every 300 seconds per threat type.
| Severity | Meaning |
|---|---|
| 🟢 Normal | No threat detected |
| 🔵 Low | Informational |
| 🟡 Medium | Potential risk |
| 🟠 High | Dangerous environment |
| 🔴 Critical | Immediate action recommended |
| Method | Description |
|---|---|
| performCheck() | Run all configured checks |
| isSecure() | Quick security status |
| startMonitoring() | Begin monitoring |
| stopMonitoring() | Stop monitoring |
| configure() | Update configuration |
| onStatusChange() | Status callback |
| onThreatDetected() | Threat callback |
| Threat | Severity |
|---|---|
| Jailbreak | 🔴 Critical |
| Reverse Engineering | 🔴 Critical |
| App Integrity Failure | 🔴 Critical |
| Hook Detection | 🔴 Critical |
| Method Swizzling | 🔴 Critical |
| Pinning Bypass | 🔴 Critical |
| Frida | 🔴 Critical |
| Attestation Failure | 🔴 Critical |
| DSK Tampering | 🔴 Critical |
| Repackaging | 🔴 Critical |
| Debugger | 🟠 High |
| Screen Recording | 🟠 High |
| Emulator | 🟡 Medium |
| VPN / Proxy | 🟡 Medium |
| Screenshot | 🟡 Medium |
<key>LSApplicationQueriesSchemes</key>
<array>
<string>cydia</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
<string>undecimus</string>
<string>checkra1n</string>
<string>taurine</string>
<string>odyssey</string>
<string>dopamine</string>
</array>| Requirement | Version |
|---|---|
| iOS | 15.0+ |
| Swift | 5.9+ |
| Xcode | 15.0+ |
DeviceSecurityKit is a client-side detection library. All checks run within the app process on the user's device, which means:
- Bypassable by a determined attacker. Anyone with full control of the device (root access, custom kernel, instrumentation frameworks) can intercept, patch, or suppress any check. No client-side security library can prevent this.
- Best used as a signal, not a gate. Treat detection results as one input into a broader risk-assessment pipeline. Combine them with server-side validation (App Attest, device posture APIs, backend anomaly detection) for defence in depth.
- False positives are possible. Some legitimate developer tools, accessibility software, enterprise MDM profiles, or VPN configurations may trigger detections. Test thoroughly with your user base and use the configuration API to disable checks that don't apply.
- Simulator environment. Several detectors are automatically disabled in the iOS Simulator (
#if targetEnvironment(simulator)) because they would always trigger. Test security-critical flows on a real device.
Issues and pull requests are welcome.
For major changes, please open an issue first.
MIT License
Created by @galahador
🛡️ Security First • Zero Dependencies • Open Source Forever
