narvy-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. narvy/__init__.py +3 -0
  2. narvy/android/__init__.py +0 -0
  3. narvy/android/source_analyzer.py +268 -0
  4. narvy/android/split_bundle.py +475 -0
  5. narvy/android_rule_context.py +196 -0
  6. narvy/apk_memory_preflight.py +248 -0
  7. narvy/auth.py +40 -0
  8. narvy/ci_templates/bitbucket.yml +25 -0
  9. narvy/ci_templates/github.yml +60 -0
  10. narvy/ci_templates/gitlab.yml +32 -0
  11. narvy/cloud/__init__.py +0 -0
  12. narvy/cloud/aws_scan.py +1188 -0
  13. narvy/comment_filter.py +134 -0
  14. narvy/crypto_taint_lite.py +82 -0
  15. narvy/decompiler.py +337 -0
  16. narvy/doctor.py +244 -0
  17. narvy/host/__init__.py +0 -0
  18. narvy/host/audit.py +157 -0
  19. narvy/host/host_knowledge.py +982 -0
  20. narvy/host/lynis_bootstrap.py +400 -0
  21. narvy/host/lynis_parser.py +358 -0
  22. narvy/host/narvy_checks.py +789 -0
  23. narvy/host/report.py +69 -0
  24. narvy/host/ssh_exec.py +219 -0
  25. narvy/ios/__init__.py +0 -0
  26. narvy/ios/binary_analyzer.py +1201 -0
  27. narvy/ios/plist_checks.py +249 -0
  28. narvy/ios/source_analyzer.py +301 -0
  29. narvy/ios/third_party_filter.py +242 -0
  30. narvy/ios/trust_all_context.py +66 -0
  31. narvy/main.py +1983 -0
  32. narvy/native_hardening.py +503 -0
  33. narvy/reporter.py +151 -0
  34. narvy/rule_engine.py +57 -0
  35. narvy/rules/android/config.yml +77 -0
  36. narvy/rules/android/crypto.yml +34 -0
  37. narvy/rules/android/secrets.yml +161 -0
  38. narvy/rules/android/storage.yml +24 -0
  39. narvy/rules/android/webview.yml +23 -0
  40. narvy/rules/android.yml +219 -0
  41. narvy/rules/ios/objc/crypto.yml +56 -0
  42. narvy/rules/ios/objc/network.yml +67 -0
  43. narvy/rules/ios/objc/secrets.yml +79 -0
  44. narvy/rules/ios/objc/storage.yml +45 -0
  45. narvy/rules/ios/objc/webview.yml +45 -0
  46. narvy/rules/ios_swift.yml +327 -0
  47. narvy/rules/web/go.yml +2837 -0
  48. narvy/rules/web/java.yml +1576 -0
  49. narvy/rules/web/javascript.yml +3683 -0
  50. narvy/rules/web/kotlin.yml +413 -0
  51. narvy/rules/web/local/csharp_narvy/config.yml +61 -0
  52. narvy/rules/web/local/csharp_narvy/crypto.yml +64 -0
  53. narvy/rules/web/local/csharp_narvy/deserialization.yml +59 -0
  54. narvy/rules/web/local/csharp_narvy/injection.yml +122 -0
  55. narvy/rules/web/local/csharp_narvy/xxe.yml +48 -0
  56. narvy/rules/web/local/java_narvy/auth_jwt.yml +134 -0
  57. narvy/rules/web/local/java_narvy/deserialization.yml +108 -0
  58. narvy/rules/web/local/java_narvy/mybatis.yml +39 -0
  59. narvy/rules/web/local/java_narvy/snakeyaml.yml +34 -0
  60. narvy/rules/web/local/java_narvy/spring_authz.yml +32 -0
  61. narvy/rules/web/local/java_narvy/spring_config.yml +67 -0
  62. narvy/rules/web/local/java_narvy/spring_hardening.yml +291 -0
  63. narvy/rules/web/local/java_narvy/sqli.yml +235 -0
  64. narvy/rules/web/local/java_narvy/xxe.yml +212 -0
  65. narvy/rules/web/php.yml +1644 -0
  66. narvy/rules/web/python.yml +3967 -0
  67. narvy/rules/web/ruby.yml +703 -0
  68. narvy/rules/web/rust.yml +258 -0
  69. narvy/rules/web/secrets.yml +1420 -0
  70. narvy/rules/web/secrets_supplement.yml +383 -0
  71. narvy/sca/__init__.py +1 -0
  72. narvy/sca/android_deps.py +349 -0
  73. narvy/sca/ios_deps.py +578 -0
  74. narvy/sca/osv_client.py +617 -0
  75. narvy/sca/web_deps.py +955 -0
  76. narvy/scope_config.py +195 -0
  77. narvy/semgrep_engine.py +219 -0
  78. narvy/stack_protector_evidence.py +96 -0
  79. narvy/third_party_filter.py +211 -0
  80. narvy/uploader.py +92 -0
  81. narvy/weak_prng_context.py +270 -0
  82. narvy/web/__init__.py +0 -0
  83. narvy/web/nuclei_binary.py +105 -0
  84. narvy/web/scan_blocklist.py +96 -0
  85. narvy/web/scanner.py +842 -0
  86. narvy/web/source_analyzer.py +714 -0
  87. narvy/web/ssrf_guard.py +374 -0
  88. narvy_cli-1.0.0.dist-info/METADATA +165 -0
  89. narvy_cli-1.0.0.dist-info/RECORD +93 -0
  90. narvy_cli-1.0.0.dist-info/WHEEL +5 -0
  91. narvy_cli-1.0.0.dist-info/entry_points.txt +2 -0
  92. narvy_cli-1.0.0.dist-info/licenses/LICENSE +202 -0
  93. narvy_cli-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,67 @@
1
+ # Objective-C transport-security checks.
2
+
3
+ - id: IOS-OBJC-NET-001
4
+ name: "Undocumented API Disables All HTTPS Certificate Validation"
5
+ pattern: 'allowsAnyHTTPSCertificateForHost'
6
+ severity: "CRITICAL"
7
+ confidence: "HIGH"
8
+ details:
9
+ cwe: "CWE-295"
10
+ masvs: "MSTG-NETWORK-3"
11
+ description: "setAllowsAnyHTTPSCertificateForHost:forHost: is a private/undocumented NSURLRequest API that disables ALL certificate validation for the given host. Its mere presence in a shipped binary is itself an App Store review red flag, and it is a trivial MITM path."
12
+ recommendation: "Remove this call entirely. Use NSURLSession with a proper URLSessionDelegate that validates the server trust (SecTrustEvaluateWithError), or implement certificate pinning."
13
+
14
+ - id: IOS-OBJC-NET-002
15
+ name: "NSURLConnection Accepts Any Certificate/Protection Space"
16
+ pattern: '(?s)canAuthenticateAgainstProtectionSpace\s*:.*?return\s+YES\s*;'
17
+ severity: "CRITICAL"
18
+ confidence: "MEDIUM"
19
+ details:
20
+ cwe: "CWE-295"
21
+ masvs: "MSTG-NETWORK-3"
22
+ description: "The NSURLConnection delegate's canAuthenticateAgainstProtectionSpace: unconditionally returns YES, meaning the connection will authenticate against ANY protection space/authentication method presented - including self-signed or attacker-controlled certificates."
23
+ recommendation: "Migrate to NSURLSession. If NSURLConnection must be kept, restrict this to only the expected authentication methods and validate the server trust before returning YES."
24
+
25
+ - id: IOS-OBJC-NET-003
26
+ name: "Continues Without Credential on Auth Challenge"
27
+ pattern: 'continueWithoutCredentialForAuthenticationChallenge\s*:'
28
+ severity: "HIGH"
29
+ confidence: "LOW"
30
+ details:
31
+ cwe: "CWE-295"
32
+ masvs: "MSTG-NETWORK-3"
33
+ description: "continueWithoutCredentialForAuthenticationChallenge: proceeds with the connection despite an unresolved authentication challenge (e.g. an untrusted server certificate). This is a low-confidence heuristic - it flags every call site, not just certificate-bypass usage; verify the surrounding logic manually."
34
+ recommendation: "Verify this is not being used to silently accept an untrusted server certificate. If it is, validate the server trust explicitly before deciding whether to proceed."
35
+
36
+ - id: IOS-OBJC-NET-004
37
+ name: "AFNetworking Certificate Validation Disabled"
38
+ pattern: 'allowInvalidCertificates\s*=\s*YES'
39
+ severity: "CRITICAL"
40
+ confidence: "HIGH"
41
+ details:
42
+ cwe: "CWE-295"
43
+ masvs: "MSTG-NETWORK-3"
44
+ description: "AFSecurityPolicy.allowInvalidCertificates is set to YES, which disables TLS certificate validation for this AFNetworking session - the app will accept any certificate, including a self-signed one from an attacker performing a MITM."
45
+ recommendation: "Set allowInvalidCertificates to NO (the default) in release builds. If pinning is required, use AFSecurityPolicy's pinning modes (AFSSLPinningModeCertificate/PublicKey) instead of disabling validation."
46
+
47
+ - id: IOS-OBJC-NET-005
48
+ name: "AFNetworking Domain Name Validation Disabled"
49
+ pattern: 'validatesDomainName\s*=\s*NO'
50
+ severity: "HIGH"
51
+ confidence: "HIGH"
52
+ details:
53
+ cwe: "CWE-297"
54
+ masvs: "MSTG-NETWORK-3"
55
+ description: "AFSecurityPolicy.validatesDomainName is set to NO, which disables hostname validation - a certificate for any domain will be accepted for this connection, enabling MITM even with a validly-signed certificate."
56
+ recommendation: "Leave validatesDomainName at its default (YES). If a specific case genuinely requires disabling it, pin the exact expected certificate/public key instead."
57
+
58
+ - id: IOS-OBJC-NET-006
59
+ name: "Hardcoded Cleartext HTTP URL"
60
+ pattern: '@"http://(?!localhost|127\.0\.0\.1)[^"]+"'
61
+ severity: "MEDIUM"
62
+ confidence: "LOW"
63
+ details:
64
+ cwe: "CWE-319"
65
+ masvs: "MSTG-NETWORK-1"
66
+ description: "A hardcoded http:// (non-TLS) URL literal is used. Traffic to this endpoint is sent in cleartext unless an ATS exception domain forces an upgrade. Low-confidence heuristic - some of these may be intentional (e.g. local dev servers, non-sensitive third-party feeds); verify manually."
67
+ recommendation: "Use https:// for any endpoint that carries sensitive data or app logic. Remove NSAllowsArbitraryLoads / per-domain HTTP exceptions from Info.plist for production builds."
@@ -0,0 +1,79 @@
1
+ # Objective-C hardcoded-credential checks.
2
+
3
+ - id: IOS-OBJC-S-001
4
+ name: "Hardcoded API Key"
5
+ pattern: '(?i)(api[_-]?key|api[_-]?secret)\s*=\s*@"[A-Za-z0-9+/=]{16,}"'
6
+ severity: "CRITICAL"
7
+ confidence: "HIGH"
8
+ details:
9
+ cwe: "CWE-798"
10
+ masvs: "MSTG-STORAGE-1"
11
+ description: "A hardcoded API key or secret token was found. Anyone who reads the source (or a source-available/leaked build) gains unauthorized access to whatever service this key authorizes."
12
+ recommendation: "Do not hardcode credentials. Retrieve them from a secure backend at runtime, or store them in the Keychain if they must persist on-device."
13
+
14
+ - id: IOS-OBJC-S-002
15
+ name: "Hardcoded Password"
16
+ pattern: '(?i)(password|passwd|pwd)\s*=\s*@"[^"]{6,}"\s*;'
17
+ severity: "CRITICAL"
18
+ confidence: "MEDIUM"
19
+ details:
20
+ cwe: "CWE-259"
21
+ masvs: "MSTG-STORAGE-1"
22
+ description: "A hardcoded password literal may have been found in the source code. Storing credentials directly in source is highly insecure."
23
+ recommendation: "Remove credentials from the code. Prompt the user or retrieve credentials from a secure backend/Keychain instead."
24
+
25
+ - id: IOS-OBJC-S-003
26
+ name: "Hardcoded Private Key"
27
+ # Require base64 key material after the header, so a bare "-----BEGIN PRIVATE KEY-----" marker constant is not flagged.
28
+ pattern: '-----BEGIN( RSA| EC| OPENSSH| DSA)? PRIVATE KEY-----[\r\n\s]+[A-Za-z0-9+/]{40,}'
29
+ severity: "CRITICAL"
30
+ confidence: "HIGH"
31
+ details:
32
+ cwe: "CWE-321"
33
+ masvs: "MSTG-CRYPTO-1"
34
+ description: "A private key block (e.g. RSA) was found embedded in the code. This completely compromises the security provided by the key."
35
+ recommendation: "Private keys should never ship inside the app bundle or source tree. Use the Keychain/Secure Enclave for on-device key material, or retrieve keys from a secure server at runtime."
36
+
37
+ - id: IOS-OBJC-S-004
38
+ name: "Hardcoded AWS Access Key ID"
39
+ pattern: 'AKIA[0-9A-Z]{16}'
40
+ severity: "CRITICAL"
41
+ confidence: "HIGH"
42
+ details:
43
+ cwe: "CWE-798"
44
+ masvs: "MSTG-STORAGE-1"
45
+ description: "An AWS Access Key ID was found hardcoded in the app. If paired with its secret key (also often nearby), this grants direct access to whatever AWS resources the key's IAM policy allows."
46
+ recommendation: "Revoke this key in the AWS IAM console immediately, then remove it from the code. Mobile apps should never hold long-lived AWS credentials - use temporary credentials via Cognito Identity Pools or a backend-issued token instead."
47
+
48
+ - id: IOS-OBJC-S-005
49
+ name: "Hardcoded Stripe Live Secret Key"
50
+ pattern: 'sk_live_[0-9a-zA-Z]{24,}'
51
+ severity: "CRITICAL"
52
+ confidence: "HIGH"
53
+ details:
54
+ cwe: "CWE-798"
55
+ masvs: "MSTG-STORAGE-1"
56
+ description: "A Stripe LIVE secret key was found hardcoded in the app. This key can create charges, issue refunds, and read all payment data on the connected Stripe account - a direct financial exposure, not just a data leak."
57
+ recommendation: "Roll this key immediately in the Stripe dashboard. Secret keys must never be shipped client-side; only publishable keys (pk_live_/pk_test_) belong in a mobile app, and all charge/refund logic must run server-side."
58
+
59
+ - id: IOS-OBJC-S-006
60
+ name: "Hardcoded JWT"
61
+ pattern: 'eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}'
62
+ severity: "MEDIUM"
63
+ confidence: "MEDIUM"
64
+ details:
65
+ cwe: "CWE-798"
66
+ masvs: "MSTG-STORAGE-1"
67
+ description: "A hardcoded JSON Web Token was found. If this is a real, live, long-lived token (as opposed to a test fixture), it grants whatever access its claims allow to anyone who reads the source."
68
+ recommendation: "Confirm whether this is test/fixture data. If it is a real token, revoke it and issue tokens dynamically per-session from the backend instead of embedding one statically."
69
+
70
+ - id: IOS-OBJC-S-007
71
+ name: "Credentials Embedded in URL"
72
+ pattern: 'https?://[^/\s:]+:[^/\s@"]+@'
73
+ severity: "HIGH"
74
+ confidence: "MEDIUM"
75
+ details:
76
+ cwe: "CWE-798"
77
+ masvs: "MSTG-STORAGE-1"
78
+ description: "A URL containing embedded username:password credentials (Basic Auth in the URL itself) was found. These credentials are visible in source, logs, and often browser/proxy history."
79
+ recommendation: "Remove credentials from the URL. Use an Authorization header set at request time from a securely stored credential, or better, an OAuth token flow."
@@ -0,0 +1,45 @@
1
+ # Objective-C local-storage checks.
2
+
3
+ - id: IOS-OBJC-STORAGE-001
4
+ name: "Sensitive Data Stored in NSUserDefaults"
5
+ pattern: '(?i)\[[\w\s.\[\]]*userdefaults[\w\s.\]]*\s+setObject\s*:[^;]*forKey\s*:\s*@"[^"]*(password|token|secret|api[_-]?key)[^"]*"'
6
+ severity: "HIGH"
7
+ confidence: "MEDIUM"
8
+ details:
9
+ cwe: "CWE-922"
10
+ masvs: "MSTG-STORAGE-1"
11
+ description: "A value is written to NSUserDefaults under a key that looks like a credential/token/secret. NSUserDefaults is a plaintext plist file, readable by anyone with filesystem access (jailbreak, backup extraction, or another process on a compromised device)."
12
+ recommendation: "Store credentials, tokens, and secrets in the Keychain (SecItemAdd with an appropriate kSecAttrAccessible level), never in NSUserDefaults."
13
+
14
+ - id: IOS-OBJC-STORAGE-002
15
+ name: "Insecure Keychain Accessibility (Always)"
16
+ pattern: 'kSecAttrAccessibleAlways(ThisDeviceOnly)?\b'
17
+ severity: "HIGH"
18
+ confidence: "HIGH"
19
+ details:
20
+ cwe: "CWE-922"
21
+ masvs: "MSTG-STORAGE-1"
22
+ description: "kSecAttrAccessibleAlways lets the Keychain item be read even while the device is locked. The non-'ThisDeviceOnly' variant additionally allows the item to be restored onto a different device from an iCloud/iTunes backup."
23
+ recommendation: "Use kSecAttrAccessibleWhenUnlockedThisDeviceOnly (or WhenPasscodeSetThisDeviceOnly for the strongest guarantee) unless the item genuinely must be available before first unlock."
24
+
25
+ - id: IOS-OBJC-STORAGE-003
26
+ name: "Sensitive Data Logged via NSLog"
27
+ pattern: '(?i)NSLog\s*\(\s*@"[^"]*(password|token|secret|api[_-]?key)[^"]*"'
28
+ severity: "MEDIUM"
29
+ confidence: "MEDIUM"
30
+ details:
31
+ cwe: "CWE-532"
32
+ masvs: "MSTG-STORAGE-3"
33
+ description: "NSLog output is readable via the device console, Console.app, and (on many crash reporters) uploaded with crash logs. Logging a value whose format string references a credential/token/secret risks leaking it."
34
+ recommendation: "Remove sensitive values from log statements entirely, or redact them (e.g. log only the last 4 characters) before logging."
35
+
36
+ - id: IOS-OBJC-STORAGE-004
37
+ name: "File Protection Explicitly Disabled"
38
+ pattern: 'NSFileProtectionNone\b'
39
+ severity: "MEDIUM"
40
+ confidence: "MEDIUM"
41
+ details:
42
+ cwe: "CWE-922"
43
+ masvs: "MSTG-STORAGE-1"
44
+ description: "NSFileProtectionNone explicitly disables Data Protection encryption for a file, making it readable even while the device is locked (e.g. after a jailbreak that bypasses the lock screen)."
45
+ recommendation: "Use NSFileProtectionCompleteUntilFirstUserAuthentication (the iOS default) or NSFileProtectionComplete for files containing sensitive data. Only use NSFileProtectionNone for genuinely non-sensitive files that must be accessible during background execution while locked."
@@ -0,0 +1,45 @@
1
+ # Objective-C WebView configuration checks.
2
+
3
+ - id: IOS-OBJC-WEBVIEW-001
4
+ name: "Deprecated UIWebView Usage"
5
+ pattern: '\bUIWebView\s*\*'
6
+ severity: "MEDIUM"
7
+ confidence: "HIGH"
8
+ details:
9
+ cwe: "CWE-1104"
10
+ masvs: "MSTG-PLATFORM-5"
11
+ description: "UIWebView is deprecated - Apple has rejected new App Store submissions using it since April 2020. It also lacks WKWebView's out-of-process JS execution and per-origin sandboxing, making JS-injection issues more impactful."
12
+ recommendation: "Migrate to WKWebView, which runs web content in a separate process and offers WKUserContentController for tighter control over injected scripts and message handlers."
13
+
14
+ - id: IOS-OBJC-WEBVIEW-002
15
+ name: "JavaScript Evaluated via String Concatenation"
16
+ pattern: 'stringByEvaluatingJavaScriptFromString\s*:\s*\[NSString stringWithFormat'
17
+ severity: "HIGH"
18
+ confidence: "MEDIUM"
19
+ details:
20
+ cwe: "CWE-79"
21
+ masvs: "MSTG-PLATFORM-5"
22
+ description: "JavaScript is built via stringWithFormat and evaluated in the WebView. If any interpolated value can be influenced by untrusted input (deep link, server response, user input), this is JavaScript injection into the WebView's context."
23
+ recommendation: "Avoid building JS strings via string formatting. If dynamic values must be passed into JS, JSON-encode them and use a fixed template, or use WKScriptMessageHandler for structured native<->JS communication instead."
24
+
25
+ - id: IOS-OBJC-WEBVIEW-003
26
+ name: "WebView Authentication Challenge Accepts Any Credential"
27
+ pattern: '(?s)webView\s*:\s*didReceiveAuthenticationChallenge\s*:.*?completionHandler\s*\(\s*NSURLSessionAuthChallengeUseCredential'
28
+ severity: "CRITICAL"
29
+ confidence: "MEDIUM"
30
+ details:
31
+ cwe: "CWE-295"
32
+ masvs: "MSTG-NETWORK-3"
33
+ description: "The WebView's authentication-challenge delegate method calls completionHandler with NSURLSessionAuthChallengeUseCredential, which accepts the credential/certificate offered without validating it - a trivial MITM path for content loaded in the WebView."
34
+ recommendation: "Validate the server trust (SecTrustEvaluateWithError against the expected certificate/public key) before calling completionHandler with UseCredential. Prefer NSURLSessionAuthChallengePerformDefaultHandling for the common case."
35
+
36
+ - id: IOS-OBJC-WEBVIEW-004
37
+ name: "Universal File Access From File URLs Enabled"
38
+ pattern: 'setAllowUniversalAccessFromFileURLs\s*:\s*YES'
39
+ severity: "HIGH"
40
+ confidence: "HIGH"
41
+ details:
42
+ cwe: "CWE-940"
43
+ masvs: "MSTG-PLATFORM-5"
44
+ description: "allowUniversalAccessFromFileURLs lets JavaScript running in a file:// context reach any origin, including making cross-origin requests and reading local files - a well-known path to universal XSS / local file exfiltration."
45
+ recommendation: "Leave allowUniversalAccessFromFileURLs at its default (NO/false) unless there is a specific, reviewed need. If local HTML must load remote resources, load it via a custom URL scheme handler instead."
@@ -0,0 +1,327 @@
1
+ # Swift source rules, authored by Narvy.
2
+ # Keychain, TLS, crypto, WebView, pasteboard, secrets.
3
+
4
+ rules:
5
+ - id: ios-swift-ecb-mode
6
+ languages: [swift]
7
+ severity: ERROR
8
+ message: >-
9
+ ECB mode is used for encryption (kCCOptionECBMode). ECB is insecure
10
+ because identical plaintext blocks encrypt to identical ciphertext
11
+ blocks, revealing patterns. Use GCM or CBC with a random IV instead.
12
+ metadata:
13
+ cwe: CWE-327
14
+ masvs: MSTG-CRYPTO-4
15
+ category: crypto
16
+ pattern-either:
17
+ - pattern: CCCrypt(..., kCCOptionECBMode, ...)
18
+ - pattern-regex: 'kCCOptionECBMode'
19
+
20
+ - id: ios-swift-weak-cipher
21
+ languages: [swift]
22
+ severity: ERROR
23
+ message: "DES/3DES/RC4 are broken ciphers (kCCAlgorithmDES/3DES/RC4). Use AES-256-GCM instead."
24
+ metadata:
25
+ cwe: CWE-327
26
+ masvs: MSTG-CRYPTO-4
27
+ category: crypto
28
+ pattern-regex: 'kCCAlgorithm(DES|3DES|RC4)\b'
29
+
30
+ - id: ios-swift-weak-hash
31
+ languages: [swift]
32
+ severity: WARNING
33
+ message: "MD5/SHA-1 are broken for security-sensitive hashing (CommonCrypto CC_MD5/CC_SHA1 or CryptoKit Insecure.MD5/Insecure.SHA1). Use SHA256+."
34
+ metadata:
35
+ cwe: CWE-328
36
+ masvs: MSTG-CRYPTO-4
37
+ category: crypto
38
+ pattern-either:
39
+ - pattern: CC_MD5(...)
40
+ - pattern: CC_SHA1(...)
41
+ - pattern: Insecure.MD5.hash(...)
42
+ - pattern: Insecure.SHA1.hash(...)
43
+ - pattern: Insecure.MD5()
44
+ - pattern: Insecure.SHA1()
45
+
46
+ - id: ios-swift-weak-prng
47
+ languages: [swift]
48
+ severity: ERROR
49
+ message: "rand()/random()/drand48() are not cryptographically secure. Use SecRandomCopyBytes or CryptoKit for security-sensitive values."
50
+ metadata:
51
+ cwe: CWE-338
52
+ masvs: MSTG-CRYPTO-6
53
+ category: crypto
54
+ pattern-either:
55
+ - pattern: rand()
56
+ - pattern: random()
57
+ - pattern: drand48()
58
+ - pattern: arc4random() % $N
59
+
60
+ - id: ios-swift-hardcoded-crypto-key
61
+ languages: [swift]
62
+ severity: ERROR
63
+ message: >-
64
+ A symmetric encryption key/passphrase is built directly from a string
65
+ literal (SymmetricKey/CCCrypt/CCCryptorCreate). Anyone who reads the
66
+ source (or decompiles a source-available build) recovers the exact
67
+ key used to encrypt/decrypt all protected data.
68
+ metadata:
69
+ cwe: CWE-321
70
+ masvs: MSTG-CRYPTO-1
71
+ category: crypto
72
+ pattern-either:
73
+ - pattern: 'SymmetricKey(data: Data("...".utf8))'
74
+ - pattern: 'SymmetricKey(data: "...".data(using: $ENC)!)'
75
+ - pattern: CCCrypt(..., "...", ...)
76
+ - pattern: CCCryptorCreate(..., "...", ...)
77
+
78
+ - id: ios-swift-trust-all-certs
79
+ languages: [swift]
80
+ severity: ERROR
81
+ message: >-
82
+ URLSession authentication challenge handler calls completionHandler
83
+ with .useCredential unconditionally - this accepts ANY server
84
+ certificate, disabling TLS validation entirely (trivial MITM).
85
+ metadata:
86
+ cwe: CWE-295
87
+ masvs: MSTG-NETWORK-3
88
+ category: network
89
+ pattern-either:
90
+ - pattern: 'completionHandler(.useCredential, URLCredential(trust: $T))'
91
+ - pattern: 'completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: $T))'
92
+
93
+ - id: ios-swift-webview-js-untrusted-concat
94
+ languages: [swift]
95
+ severity: ERROR
96
+ message: >-
97
+ evaluateJavaScript() is called with a string built via concatenation
98
+ or interpolation instead of a fixed literal. If any part of the
99
+ string can be influenced by untrusted input (deep link, server
100
+ response, user input), this is JavaScript injection into the WebView.
101
+ metadata:
102
+ cwe: CWE-79
103
+ masvs: MSTG-PLATFORM-5
104
+ category: webview
105
+ patterns:
106
+ - pattern-either:
107
+ - pattern: $WV.evaluateJavaScript($A + $B, ...)
108
+ - pattern: $WV.evaluateJavaScript("...\($X)...", ...)
109
+
110
+ - id: ios-swift-uiwebview-deprecated
111
+ languages: [swift]
112
+ severity: WARNING
113
+ message: >-
114
+ UIWebView is deprecated (Apple rejects new App Store submissions using
115
+ it) and lacks WKWebView's process-isolation / modern security
116
+ protections (no per-origin sandboxing of JS, weaker WKUserContentController
117
+ controls). Migrate to WKWebView.
118
+ metadata:
119
+ cwe: CWE-1104
120
+ masvs: MSTG-PLATFORM-5
121
+ category: webview
122
+ pattern: UIWebView(...)
123
+
124
+ - id: ios-swift-log-sensitive-data
125
+ languages: [swift]
126
+ severity: WARNING
127
+ message: >-
128
+ A log statement (print/NSLog/os_log) includes a value whose name
129
+ looks like a credential/token/secret - readable via device console
130
+ logs, crash reporters, or (for print) even shipped in release builds
131
+ if not stripped.
132
+ metadata:
133
+ cwe: CWE-532
134
+ masvs: MSTG-STORAGE-3
135
+ category: logging
136
+ patterns:
137
+ - pattern-either:
138
+ - pattern: print($MSG)
139
+ - pattern: NSLog($MSG, ...)
140
+ - pattern: os_log($MSG, ...)
141
+ - metavariable-pattern:
142
+ metavariable: $MSG
143
+ patterns:
144
+ - pattern-regex: '(?i)(password|token|secret|api[_-]?key)'
145
+
146
+ - id: ios-swift-keychain-insecure-accessibility
147
+ languages: [swift]
148
+ severity: WARNING
149
+ message: >-
150
+ kSecAttrAccessibleAlways(ThisDeviceOnly) lets the Keychain item be
151
+ read even while the device is locked, and the non-"ThisDeviceOnly"
152
+ variants let it be restored onto a different device from an iCloud/
153
+ iTunes backup. Prefer kSecAttrAccessibleWhenUnlockedThisDeviceOnly.
154
+ metadata:
155
+ cwe: CWE-922
156
+ masvs: MSTG-STORAGE-1
157
+ category: storage
158
+ pattern-regex: 'kSecAttrAccessibleAlways\b'
159
+
160
+ - id: ios-swift-sql-injection
161
+ languages: [swift]
162
+ severity: ERROR
163
+ message: >-
164
+ SQL built via string concatenation/interpolation is passed to a raw
165
+ exec/query call (sqlite3_exec or an ORM's rawQuery-style API). Use
166
+ parameterized queries (bound placeholders) instead.
167
+ metadata:
168
+ cwe: CWE-89
169
+ masvs: MSTG-PLATFORM-2
170
+ category: injection
171
+ pattern-either:
172
+ - pattern: sqlite3_exec($DB, $A + $B, ...)
173
+ - pattern: sqlite3_exec($DB, "...\($X)...", ...)
174
+ - pattern: sqlite3_prepare_v2($DB, $A + $B, ...)
175
+ - pattern: sqlite3_prepare_v2($DB, "...\($X)...", ...)
176
+ - pattern: sqlite3_prepare($DB, "...\($X)...", ...)
177
+ - pattern: $DB.executeQuery("...\($X)...", ...)
178
+ - pattern: $DB.executeQuery($A + $B, ...)
179
+ - pattern: $DB.executeUpdate("...\($X)...", ...)
180
+ - pattern: $DB.executeUpdate($A + $B, ...)
181
+
182
+ - id: ios-swift-sql-injection-string-build
183
+ languages: [swift]
184
+ severity: ERROR
185
+ message: >-
186
+ A SQL statement (SELECT/INSERT/UPDATE/DELETE/...) injects a value via
187
+ Swift string interpolation (\(...)) or concatenation (+). If the
188
+ interpolated/concatenated value derives from user input this is SQL
189
+ injection. Use parameterized queries with bound placeholders instead.
190
+ metadata:
191
+ cwe: CWE-89
192
+ masvs: MSTG-PLATFORM-2
193
+ category: injection
194
+ pattern-regex: |-
195
+ (?i)"\s*(?:SELECT\b[^"\n]*?\bFROM\b|INSERT\s+INTO\b|UPDATE\b[^"\n]*?\bSET\b|DELETE\s+FROM\b|REPLACE\s+INTO\b|(?:DROP|ALTER|CREATE)\s+TABLE\b)(?:[^"\n]*?'[^'\n]*\\\(|[^"\n]*?(?:=|==|<>|!=|<=|>=|<|>|\bLIKE\b|\bGLOB\b)\s*\\\(|[^"\n]*?(?:=|==|<>|!=|<=|>=|<|>|\bLIKE\b|\bGLOB\b)\s*"\s*\+)
196
+
197
+ - id: ios-swift-cleartext-http-url
198
+ languages: [swift]
199
+ severity: WARNING
200
+ message: >-
201
+ A hardcoded http:// (non-TLS) URL literal is used. Traffic to this
202
+ endpoint is sent in cleartext unless ATS exception domains force it
203
+ to upgrade - verify this isn't a real network destination.
204
+ metadata:
205
+ cwe: CWE-319
206
+ masvs: MSTG-NETWORK-1
207
+ category: network
208
+ pattern-regex: '"http://(?!localhost|127\.0\.0\.1)[^"]+"'
209
+
210
+ # Hardcoded cloud / third-party credentials: fixed-prefix high-entropy tokens.
211
+ - id: ios-swift-hardcoded-aws-access-key
212
+ languages: [swift]
213
+ severity: ERROR
214
+ message: >-
215
+ An AWS Access Key ID (AKIA...) is hardcoded in Swift source. Paired
216
+ with its secret (often nearby), it grants direct access to whatever the
217
+ key's IAM policy allows. Revoke it in IAM now and remove it; mobile apps
218
+ should use temporary credentials (Cognito Identity Pools or a
219
+ backend-issued token), never a long-lived AWS key.
220
+ metadata:
221
+ cwe: CWE-798
222
+ masvs: MSTG-STORAGE-1
223
+ category: secrets
224
+ pattern-regex: '\bAKIA[0-9A-Z]{16}\b'
225
+
226
+ - id: ios-swift-hardcoded-google-api-key
227
+ languages: [swift]
228
+ severity: ERROR
229
+ message: >-
230
+ A Google API key (AIza...) is hardcoded in Swift source. Depending on
231
+ the key's API restrictions this can be abused for billed API calls or
232
+ data access. Restrict/rotate the key in the Google Cloud console and
233
+ load it from a secure backend instead of embedding it.
234
+ metadata:
235
+ cwe: CWE-798
236
+ masvs: MSTG-STORAGE-1
237
+ category: secrets
238
+ pattern-regex: '\bAIza[0-9A-Za-z\-_]{35}\b'
239
+
240
+ - id: ios-swift-hardcoded-stripe-secret-key
241
+ languages: [swift]
242
+ severity: ERROR
243
+ message: >-
244
+ A Stripe LIVE secret key (sk_live_...) is hardcoded in Swift source.
245
+ It can create charges, issue refunds and read all payment data - a
246
+ direct financial exposure. Roll it in the Stripe dashboard immediately;
247
+ only publishable keys (pk_live_/pk_test_) belong in a mobile app, and
248
+ charge/refund logic must run server-side.
249
+ metadata:
250
+ cwe: CWE-798
251
+ masvs: MSTG-STORAGE-1
252
+ category: secrets
253
+ pattern-regex: '\bsk_live_[0-9a-zA-Z]{24,}\b'
254
+
255
+ - id: ios-swift-hardcoded-github-token
256
+ languages: [swift]
257
+ severity: ERROR
258
+ message: >-
259
+ A GitHub personal-access token (ghp_...) is hardcoded in Swift source.
260
+ Anyone who reads it gains whatever repo/org access the token carries.
261
+ Revoke it in GitHub settings and remove it from the source tree.
262
+ metadata:
263
+ cwe: CWE-798
264
+ masvs: MSTG-STORAGE-1
265
+ category: secrets
266
+ pattern-regex: '\bghp_[A-Za-z0-9]{36}\b'
267
+
268
+ - id: ios-swift-hardcoded-slack-token
269
+ languages: [swift]
270
+ severity: ERROR
271
+ message: >-
272
+ A Slack token (xox[baprs]-...) is hardcoded in Swift source. It grants
273
+ whatever workspace access the token type allows. Revoke it in Slack and
274
+ remove it; load it from a secure backend if the app truly needs it.
275
+ metadata:
276
+ cwe: CWE-798
277
+ masvs: MSTG-STORAGE-1
278
+ category: secrets
279
+ pattern-regex: '\bxox[baprs]-[0-9A-Za-z-]{10,48}\b'
280
+
281
+ - id: ios-swift-hardcoded-private-key
282
+ languages: [swift]
283
+ severity: ERROR
284
+ message: >-
285
+ A PEM private-key block is embedded in Swift source. Shipping a private
286
+ key inside the app bundle fully compromises whatever it protects. Use
287
+ the Keychain / Secure Enclave for on-device key material, or fetch keys
288
+ from a secure server at runtime.
289
+ metadata:
290
+ cwe: CWE-321
291
+ masvs: MSTG-CRYPTO-1
292
+ category: secrets
293
+ # Require base64 key material after the header, so a bare "-----BEGIN PRIVATE KEY-----" marker constant is not flagged.
294
+ pattern-regex: '-----BEGIN( RSA| EC| OPENSSH| DSA)? PRIVATE KEY-----[\r\n\s]+[A-Za-z0-9+/]{40,}'
295
+
296
+ - id: ios-swift-credentials-in-url
297
+ languages: [swift]
298
+ severity: WARNING
299
+ message: >-
300
+ A URL with embedded username:password credentials (Basic Auth in the
301
+ URL) is hardcoded in Swift source. These credentials leak into logs,
302
+ proxies and crash reports. Use an Authorization header set at request
303
+ time from a securely stored credential, or an OAuth token flow.
304
+ metadata:
305
+ cwe: CWE-798
306
+ masvs: MSTG-STORAGE-1
307
+ category: secrets
308
+ pattern-regex: '"https?://[^/\s:"]+:[^/\s@"]+@'
309
+
310
+ - id: ios-swift-userdefaults-sensitive-data
311
+ languages: [swift]
312
+ severity: WARNING
313
+ message: >-
314
+ A value is written to UserDefaults under a key that looks like a
315
+ credential/token/secret. UserDefaults (plist-backed) is unencrypted
316
+ and readable by anyone with filesystem access (jailbreak, backup
317
+ extraction) - use the Keychain for secrets instead.
318
+ metadata:
319
+ cwe: CWE-922
320
+ masvs: MSTG-STORAGE-1
321
+ category: storage
322
+ patterns:
323
+ - pattern: '$UD.set($VALUE, forKey: $KEY)'
324
+ - metavariable-pattern:
325
+ metavariable: $KEY
326
+ patterns:
327
+ - pattern-regex: '(?i)"[^"]*(password|token|secret|api[_-]?key)[^"]*"'