@intentsolutionsio/penetration-tester 2.0.0 → 3.0.4

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 (112) hide show
  1. package/.claude-plugin/plugin.json +8 -3
  2. package/README.md +8 -0
  3. package/commands/pentest.md +5 -0
  4. package/package.json +8 -3
  5. package/skills/analyzing-tls-config/SKILL.md +221 -0
  6. package/skills/analyzing-tls-config/references/AUTHORIZATION.md +133 -0
  7. package/skills/analyzing-tls-config/references/PLAYBOOK.md +267 -0
  8. package/skills/analyzing-tls-config/references/THEORY.md +128 -0
  9. package/skills/analyzing-tls-config/scripts/analyze_tls.py +415 -0
  10. package/skills/auditing-cors-policy/SKILL.md +186 -0
  11. package/skills/auditing-cors-policy/references/PLAYBOOK.md +220 -0
  12. package/skills/auditing-cors-policy/references/THEORY.md +142 -0
  13. package/skills/auditing-cors-policy/scripts/audit_cors.py +350 -0
  14. package/skills/auditing-npm-dependencies/SKILL.md +254 -0
  15. package/skills/auditing-npm-dependencies/references/PLAYBOOK.md +175 -0
  16. package/skills/auditing-npm-dependencies/references/THEORY.md +122 -0
  17. package/skills/auditing-npm-dependencies/scripts/audit_npm.py +408 -0
  18. package/skills/auditing-python-dependencies/SKILL.md +251 -0
  19. package/skills/auditing-python-dependencies/references/PLAYBOOK.md +193 -0
  20. package/skills/auditing-python-dependencies/references/THEORY.md +122 -0
  21. package/skills/auditing-python-dependencies/scripts/audit_python.py +459 -0
  22. package/skills/checking-http-security-headers/SKILL.md +176 -0
  23. package/skills/checking-http-security-headers/references/PLAYBOOK.md +212 -0
  24. package/skills/checking-http-security-headers/references/THEORY.md +137 -0
  25. package/skills/checking-http-security-headers/scripts/check_headers.py +362 -0
  26. package/skills/checking-license-compliance/SKILL.md +225 -0
  27. package/skills/checking-license-compliance/references/PLAYBOOK.md +161 -0
  28. package/skills/checking-license-compliance/references/THEORY.md +152 -0
  29. package/skills/checking-license-compliance/scripts/check_licenses.py +461 -0
  30. package/skills/composing-vulnerability-report/SKILL.md +212 -0
  31. package/skills/composing-vulnerability-report/references/PLAYBOOK.md +180 -0
  32. package/skills/composing-vulnerability-report/references/THEORY.md +178 -0
  33. package/skills/composing-vulnerability-report/scripts/compose_report.py +396 -0
  34. package/skills/confirming-pentest-authorization/SKILL.md +247 -0
  35. package/skills/confirming-pentest-authorization/references/PLAYBOOK.md +189 -0
  36. package/skills/confirming-pentest-authorization/references/THEORY.md +167 -0
  37. package/skills/confirming-pentest-authorization/scripts/check_authorization.py +457 -0
  38. package/skills/defining-pentest-scope/SKILL.md +227 -0
  39. package/skills/defining-pentest-scope/references/PLAYBOOK.md +238 -0
  40. package/skills/defining-pentest-scope/references/THEORY.md +170 -0
  41. package/skills/defining-pentest-scope/scripts/define_scope.py +472 -0
  42. package/skills/detecting-command-injection-patterns/SKILL.md +144 -0
  43. package/skills/detecting-command-injection-patterns/references/PLAYBOOK.md +302 -0
  44. package/skills/detecting-command-injection-patterns/references/THEORY.md +206 -0
  45. package/skills/detecting-command-injection-patterns/scripts/scan_cmdi.py +290 -0
  46. package/skills/detecting-debug-endpoints/SKILL.md +207 -0
  47. package/skills/detecting-debug-endpoints/references/PLAYBOOK.md +402 -0
  48. package/skills/detecting-debug-endpoints/references/THEORY.md +218 -0
  49. package/skills/detecting-debug-endpoints/scripts/probe_debug.py +518 -0
  50. package/skills/detecting-directory-listing/SKILL.md +206 -0
  51. package/skills/detecting-directory-listing/references/PLAYBOOK.md +277 -0
  52. package/skills/detecting-directory-listing/references/THEORY.md +203 -0
  53. package/skills/detecting-directory-listing/scripts/probe_directory_listing.py +180 -0
  54. package/skills/detecting-eval-exec-usage/SKILL.md +128 -0
  55. package/skills/detecting-eval-exec-usage/references/PLAYBOOK.md +306 -0
  56. package/skills/detecting-eval-exec-usage/references/THEORY.md +159 -0
  57. package/skills/detecting-eval-exec-usage/scripts/scan_eval.py +223 -0
  58. package/skills/detecting-exposed-secrets-files/SKILL.md +179 -0
  59. package/skills/detecting-exposed-secrets-files/references/PLAYBOOK.md +274 -0
  60. package/skills/detecting-exposed-secrets-files/references/THEORY.md +174 -0
  61. package/skills/detecting-exposed-secrets-files/scripts/probe_secrets.py +207 -0
  62. package/skills/detecting-insecure-deserialization/SKILL.md +148 -0
  63. package/skills/detecting-insecure-deserialization/references/PLAYBOOK.md +333 -0
  64. package/skills/detecting-insecure-deserialization/references/THEORY.md +199 -0
  65. package/skills/detecting-insecure-deserialization/scripts/scan_deserialization.py +250 -0
  66. package/skills/detecting-sql-injection-patterns/SKILL.md +161 -0
  67. package/skills/detecting-sql-injection-patterns/references/PLAYBOOK.md +317 -0
  68. package/skills/detecting-sql-injection-patterns/references/THEORY.md +261 -0
  69. package/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py +354 -0
  70. package/skills/detecting-ssl-cert-issues/SKILL.md +182 -0
  71. package/skills/detecting-ssl-cert-issues/references/PLAYBOOK.md +203 -0
  72. package/skills/detecting-ssl-cert-issues/references/THEORY.md +133 -0
  73. package/skills/detecting-ssl-cert-issues/scripts/check_cert_chain.py +481 -0
  74. package/skills/detecting-weak-cryptography/SKILL.md +147 -0
  75. package/skills/detecting-weak-cryptography/references/PLAYBOOK.md +466 -0
  76. package/skills/detecting-weak-cryptography/references/THEORY.md +194 -0
  77. package/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py +417 -0
  78. package/skills/fingerprinting-server-software/SKILL.md +191 -0
  79. package/skills/fingerprinting-server-software/references/PLAYBOOK.md +337 -0
  80. package/skills/fingerprinting-server-software/references/THEORY.md +183 -0
  81. package/skills/fingerprinting-server-software/scripts/fingerprint_server.py +347 -0
  82. package/skills/generating-executive-summary/SKILL.md +261 -0
  83. package/skills/generating-executive-summary/references/PLAYBOOK.md +201 -0
  84. package/skills/generating-executive-summary/references/THEORY.md +195 -0
  85. package/skills/generating-executive-summary/scripts/exec_summary.py +538 -0
  86. package/skills/mapping-findings-to-owasp-top10/SKILL.md +235 -0
  87. package/skills/mapping-findings-to-owasp-top10/references/PLAYBOOK.md +193 -0
  88. package/skills/mapping-findings-to-owasp-top10/references/THEORY.md +160 -0
  89. package/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py +540 -0
  90. package/skills/performing-penetration-testing/SKILL.md +282 -190
  91. package/skills/performing-penetration-testing/references/OWASP_TOP_10.md +22 -0
  92. package/skills/performing-penetration-testing/references/REMEDIATION_PLAYBOOK.md +46 -0
  93. package/skills/performing-penetration-testing/references/SECURITY_HEADERS.md +41 -0
  94. package/skills/performing-penetration-testing/scripts/code_security_scanner.py +144 -79
  95. package/skills/performing-penetration-testing/scripts/dependency_auditor.py +116 -93
  96. package/skills/performing-penetration-testing/scripts/security_scanner.py +574 -446
  97. package/skills/probing-dangerous-http-methods/SKILL.md +182 -0
  98. package/skills/probing-dangerous-http-methods/references/PLAYBOOK.md +234 -0
  99. package/skills/probing-dangerous-http-methods/references/THEORY.md +145 -0
  100. package/skills/probing-dangerous-http-methods/scripts/probe_methods.py +263 -0
  101. package/skills/recording-pentest-engagement/SKILL.md +253 -0
  102. package/skills/recording-pentest-engagement/references/PLAYBOOK.md +203 -0
  103. package/skills/recording-pentest-engagement/references/THEORY.md +195 -0
  104. package/skills/recording-pentest-engagement/scripts/record_engagement.py +461 -0
  105. package/skills/scanning-for-hardcoded-secrets/SKILL.md +215 -0
  106. package/skills/scanning-for-hardcoded-secrets/references/PLAYBOOK.md +325 -0
  107. package/skills/scanning-for-hardcoded-secrets/references/THEORY.md +175 -0
  108. package/skills/scanning-for-hardcoded-secrets/scripts/scan_secrets.py +395 -0
  109. package/skills/tracing-transitive-vulnerabilities/SKILL.md +235 -0
  110. package/skills/tracing-transitive-vulnerabilities/references/PLAYBOOK.md +233 -0
  111. package/skills/tracing-transitive-vulnerabilities/references/THEORY.md +138 -0
  112. package/skills/tracing-transitive-vulnerabilities/scripts/trace_vulns.py +484 -0
@@ -0,0 +1,466 @@
1
+ # Weak-Cryptography Remediation Playbook
2
+
3
+ Per-language migrations from the canonical weak primitives to the
4
+ modern replacements.
5
+
6
+ ## Python — `hashlib` + `cryptography` + `secrets`
7
+
8
+ ### MD5 / SHA-1 → SHA-256
9
+
10
+ ```python
11
+ # Before
12
+ import hashlib
13
+ h = hashlib.md5(data).hexdigest()
14
+
15
+ # After
16
+ h = hashlib.sha256(data).hexdigest()
17
+ # Even better: BLAKE2b
18
+ h = hashlib.blake2b(data).hexdigest()
19
+ ```
20
+
21
+ ### DES / 3DES / RC4 → AES-256-GCM
22
+
23
+ ```python
24
+ # Before (Cryptodome DES)
25
+ from Cryptodome.Cipher import DES
26
+ c = DES.new(key, DES.MODE_CBC, iv)
27
+
28
+ # After (cryptography library AES-GCM)
29
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
30
+ key = AESGCM.generate_key(bit_length=256)
31
+ aesgcm = AESGCM(key)
32
+ nonce = os.urandom(12)
33
+ ct = aesgcm.encrypt(nonce, plaintext, associated_data=None)
34
+ ```
35
+
36
+ ### ECB → GCM
37
+
38
+ ```python
39
+ # Before
40
+ cipher = AES.new(key, AES.MODE_ECB)
41
+
42
+ # After (AEAD, no separate HMAC needed)
43
+ aesgcm = AESGCM(key)
44
+ ct = aesgcm.encrypt(nonce, plaintext, None)
45
+ ```
46
+
47
+ ### Password hashing
48
+
49
+ ```python
50
+ # Before (insecure)
51
+ import hashlib
52
+ hash_ = hashlib.sha256(password.encode()).hexdigest()
53
+
54
+ # After (argon2id, recommended)
55
+ from argon2 import PasswordHasher
56
+ ph = PasswordHasher()
57
+ hash_ = ph.hash(password) # includes salt + work factor in output
58
+ # Verify:
59
+ try:
60
+ ph.verify(hash_, password) # raises on mismatch
61
+ except VerifyMismatchError:
62
+ ...
63
+
64
+ # Alternative: bcrypt (still acceptable)
65
+ import bcrypt
66
+ hash_ = bcrypt.hashpw(password.encode(), bcrypt.gensalt(12))
67
+ bcrypt.checkpw(password.encode(), hash_)
68
+ ```
69
+
70
+ ### Crypto random
71
+
72
+ ```python
73
+ # Before
74
+ import random
75
+ token = ''.join(random.choices('abc...', k=32))
76
+
77
+ # After
78
+ import secrets
79
+ token = secrets.token_urlsafe(32)
80
+ # Or for raw bytes:
81
+ random_bytes = secrets.token_bytes(32)
82
+ ```
83
+
84
+ ### TLS verification
85
+
86
+ ```python
87
+ # Before
88
+ resp = requests.get(url, verify=False)
89
+
90
+ # After (default — verify=True is implicit)
91
+ resp = requests.get(url)
92
+
93
+ # If you need a custom CA:
94
+ resp = requests.get(url, verify="/path/to/ca-bundle.crt")
95
+ ```
96
+
97
+ ## Node.js — `crypto` module
98
+
99
+ ### Hash migration
100
+
101
+ ```javascript
102
+ // Before
103
+ const md5 = crypto.createHash('md5').update(data).digest('hex');
104
+
105
+ // After
106
+ const sha256 = crypto.createHash('sha256').update(data).digest('hex');
107
+ ```
108
+
109
+ ### Cipher migration
110
+
111
+ ```javascript
112
+ // Before
113
+ const c = crypto.createCipheriv('des-ede3-cbc', key, iv);
114
+
115
+ // After (AES-256-GCM AEAD)
116
+ const iv = crypto.randomBytes(12);
117
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
118
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
119
+ const authTag = cipher.getAuthTag();
120
+ // Store [iv, encrypted, authTag] together
121
+ ```
122
+
123
+ ### Crypto random
124
+
125
+ ```javascript
126
+ // Before
127
+ const sessionId = Math.random().toString(36); // NOT crypto-grade
128
+
129
+ // After
130
+ const sessionId = crypto.randomBytes(16).toString('hex');
131
+ // Or:
132
+ const sessionId = crypto.randomUUID();
133
+ ```
134
+
135
+ ### Password hashing
136
+
137
+ ```javascript
138
+ // Before
139
+ const hash = crypto.createHash('sha256').update(password).digest('hex');
140
+
141
+ // After (bcrypt)
142
+ const bcrypt = require('bcrypt');
143
+ const hash = await bcrypt.hash(password, 12);
144
+ const ok = await bcrypt.compare(password, hash);
145
+
146
+ // After (argon2 — preferred)
147
+ const argon2 = require('argon2');
148
+ const hash = await argon2.hash(password, { type: argon2.argon2id });
149
+ const ok = await argon2.verify(hash, password);
150
+ ```
151
+
152
+ ### TLS verification (Node)
153
+
154
+ ```javascript
155
+ // Before
156
+ const https = require('https');
157
+ const agent = new https.Agent({ rejectUnauthorized: false });
158
+ fetch(url, { agent });
159
+
160
+ // After: just don't pass the agent
161
+ fetch(url); // verification on by default
162
+
163
+ // For custom CA:
164
+ const agent = new https.Agent({ ca: fs.readFileSync('/path/to/ca.crt') });
165
+ ```
166
+
167
+ ### Env var TLS bypass — REMOVE
168
+
169
+ ```bash
170
+ # Before — anywhere in startup scripts
171
+ export NODE_TLS_REJECT_UNAUTHORIZED=0
172
+
173
+ # After: remove the line entirely
174
+ ```
175
+
176
+ ## Java — `java.security` + Bouncy Castle
177
+
178
+ ### MessageDigest migration
179
+
180
+ ```java
181
+ // Before
182
+ MessageDigest md = MessageDigest.getInstance("MD5");
183
+
184
+ // After
185
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
186
+ ```
187
+
188
+ ### Cipher migration
189
+
190
+ ```java
191
+ // Before
192
+ Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
193
+
194
+ // After (AES-256-GCM)
195
+ SecureRandom random = new SecureRandom();
196
+ byte[] iv = new byte[12];
197
+ random.nextBytes(iv);
198
+ GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
199
+ Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
200
+ c.init(Cipher.ENCRYPT_MODE, key, gcmSpec);
201
+ byte[] ciphertext = c.doFinal(plaintext);
202
+ ```
203
+
204
+ ### SecureRandom
205
+
206
+ ```java
207
+ // Before
208
+ Random rand = new Random();
209
+ byte[] keyBytes = new byte[32];
210
+ rand.nextBytes(keyBytes);
211
+
212
+ // After
213
+ SecureRandom rand = new SecureRandom();
214
+ byte[] keyBytes = new byte[32];
215
+ rand.nextBytes(keyBytes);
216
+ ```
217
+
218
+ ### Password hashing (use Spring Security or library)
219
+
220
+ ```java
221
+ // Spring Security 5.0+
222
+ PasswordEncoder encoder = new BCryptPasswordEncoder(12);
223
+ String hash = encoder.encode(rawPassword);
224
+ boolean ok = encoder.matches(rawPassword, hash);
225
+
226
+ // Argon2id via password4j
227
+ import com.password4j.Password;
228
+ String hash = Password.hash(rawPassword).withArgon2().getResult();
229
+ boolean ok = Password.check(rawPassword, hash).withArgon2();
230
+ ```
231
+
232
+ ### TrustManager — never trust everything
233
+
234
+ ```java
235
+ // Before (DANGEROUS)
236
+ TrustManager[] trustAll = new TrustManager[] {
237
+ new X509TrustManager() {
238
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {}
239
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {}
240
+ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
241
+ }
242
+ };
243
+
244
+ // After: just use the default
245
+ SSLContext ctx = SSLContext.getInstance("TLS");
246
+ ctx.init(null, null, null); // null = JVM default trust store
247
+
248
+ // For custom CA: load it into a KeyStore and pass to TrustManagerFactory.
249
+ ```
250
+
251
+ ## Go — `crypto/aes` + `crypto/rand` + `golang.org/x/crypto`
252
+
253
+ ### Hash migration
254
+
255
+ ```go
256
+ // Before
257
+ import "crypto/md5"
258
+ h := md5.Sum(data)
259
+
260
+ // After
261
+ import "crypto/sha256"
262
+ h := sha256.Sum256(data)
263
+ ```
264
+
265
+ ### Cipher migration
266
+
267
+ ```go
268
+ // Before
269
+ import "crypto/des"
270
+ block, _ := des.NewTripleDESCipher(key)
271
+
272
+ // After (AES-GCM)
273
+ import (
274
+ "crypto/aes"
275
+ "crypto/cipher"
276
+ "crypto/rand"
277
+ )
278
+ block, _ := aes.NewCipher(key) // key: 16, 24, or 32 bytes
279
+ gcm, _ := cipher.NewGCM(block)
280
+ nonce := make([]byte, gcm.NonceSize())
281
+ rand.Read(nonce)
282
+ ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
283
+ ```
284
+
285
+ ### Crypto random
286
+
287
+ ```go
288
+ // Before
289
+ import "math/rand"
290
+ b := make([]byte, 32)
291
+ rand.Read(b) // PREDICTABLE
292
+
293
+ // After
294
+ import "crypto/rand"
295
+ b := make([]byte, 32)
296
+ rand.Read(b) // crypto-grade
297
+ ```
298
+
299
+ ### Password hashing
300
+
301
+ ```go
302
+ // bcrypt
303
+ import "golang.org/x/crypto/bcrypt"
304
+ hash, _ := bcrypt.GenerateFromPassword([]byte(password), 12)
305
+ err := bcrypt.CompareHashAndPassword(hash, []byte(password))
306
+
307
+ // argon2id
308
+ import "golang.org/x/crypto/argon2"
309
+ salt := make([]byte, 16)
310
+ rand.Read(salt)
311
+ hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
312
+ ```
313
+
314
+ ### TLS verification
315
+
316
+ ```go
317
+ // Before
318
+ tr := &http.Transport{
319
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
320
+ }
321
+
322
+ // After: just don't set TLSClientConfig at all (defaults are safe)
323
+ client := &http.Client{}
324
+ // Or for a custom CA:
325
+ caCert, _ := os.ReadFile("ca.crt")
326
+ caPool := x509.NewCertPool()
327
+ caPool.AppendCertsFromPEM(caCert)
328
+ tr := &http.Transport{TLSClientConfig: &tls.Config{RootCAs: caPool}}
329
+ ```
330
+
331
+ ## PHP — `openssl_*` + `password_hash` + `random_bytes`
332
+
333
+ ### Cipher migration
334
+
335
+ ```php
336
+ // Before
337
+ $ct = openssl_encrypt($pt, 'des-ede-cbc', $key, 0, $iv);
338
+
339
+ // After
340
+ $iv = random_bytes(12);
341
+ $tag = '';
342
+ $ct = openssl_encrypt($pt, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
343
+ // Store [iv, ct, tag]
344
+ ```
345
+
346
+ ### Password hashing
347
+
348
+ ```php
349
+ // Before
350
+ $hash = md5($password);
351
+
352
+ // After
353
+ $hash = password_hash($password, PASSWORD_BCRYPT);
354
+ // PHP 7.2+: argon2i; PHP 7.3+: argon2id
355
+ $hash = password_hash($password, PASSWORD_ARGON2ID);
356
+ $ok = password_verify($password, $hash);
357
+ ```
358
+
359
+ ### Crypto random
360
+
361
+ ```php
362
+ // Before
363
+ $token = bin2hex(mt_rand(0, PHP_INT_MAX));
364
+
365
+ // After
366
+ $token = bin2hex(random_bytes(32));
367
+ ```
368
+
369
+ ### cURL TLS verification — REMOVE the disable
370
+
371
+ ```php
372
+ // Before (DANGEROUS)
373
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
374
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
375
+
376
+ // After: omit those calls. Defaults are verify=true.
377
+ // For custom CA:
378
+ curl_setopt($ch, CURLOPT_CAINFO, '/path/to/ca-bundle.crt');
379
+ ```
380
+
381
+ ## C# / .NET
382
+
383
+ ### Hash migration
384
+
385
+ ```csharp
386
+ // Before
387
+ using (var md5 = MD5.Create()) { var h = md5.ComputeHash(data); }
388
+
389
+ // After
390
+ using (var sha = SHA256.Create()) { var h = sha.ComputeHash(data); }
391
+ ```
392
+
393
+ ### Cipher migration
394
+
395
+ ```csharp
396
+ // Before — DESCryptoServiceProvider deprecated
397
+ using var des = new DESCryptoServiceProvider();
398
+
399
+ // After — AES-GCM
400
+ using var aes = new AesGcm(key);
401
+ byte[] nonce = RandomNumberGenerator.GetBytes(12);
402
+ byte[] tag = new byte[16];
403
+ byte[] ciphertext = new byte[plaintext.Length];
404
+ aes.Encrypt(nonce, plaintext, ciphertext, tag);
405
+ ```
406
+
407
+ ### Crypto random
408
+
409
+ ```csharp
410
+ // Before
411
+ var rand = new Random();
412
+ byte[] key = new byte[32];
413
+ rand.NextBytes(key); // NOT crypto-grade
414
+
415
+ // After
416
+ byte[] key = RandomNumberGenerator.GetBytes(32);
417
+ ```
418
+
419
+ ### Password hashing
420
+
421
+ ```csharp
422
+ // .NET: use BCrypt.Net or Konscious.Security.Cryptography for argon2id
423
+ using BCrypt.Net;
424
+ string hash = BCrypt.HashPassword(password, workFactor: 12);
425
+ bool ok = BCrypt.Verify(password, hash);
426
+ ```
427
+
428
+ ### ServerCertificateValidation — never always-true
429
+
430
+ ```csharp
431
+ // Before (DANGEROUS)
432
+ ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, e) => true;
433
+
434
+ // After: remove. Defaults verify.
435
+ // For custom CA:
436
+ HttpClientHandler handler = new HttpClientHandler();
437
+ handler.ServerCertificateCustomValidationCallback = (s, c, ch, e) => {
438
+ // Real validation — verify against your own CA, not blind-true
439
+ };
440
+ ```
441
+
442
+ ## CI integration
443
+
444
+ ```yaml
445
+ - name: Weak-crypto scan
446
+ run: |
447
+ python3 plugins/security/penetration-tester/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py \
448
+ . --min-severity high --format json --output crypto-scan.json
449
+ - run: |
450
+ if jq 'length > 0' crypto-scan.json | grep -q true; then
451
+ echo "::error::Weak cryptography detected"
452
+ cat crypto-scan.json
453
+ exit 1
454
+ fi
455
+ ```
456
+
457
+ ## Verification after remediation
458
+
459
+ ```bash
460
+ python3 ${CLAUDE_PLUGIN_ROOT}/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py \
461
+ /path/to/repo --min-severity medium
462
+ ```
463
+
464
+ Expected: exit 0, zero MEDIUM-or-higher findings. LOW findings on
465
+ MD5/SHA-1 used in legitimate non-security contexts (content
466
+ addressing, dedup) are acceptable; document each.
@@ -0,0 +1,194 @@
1
+ # Weak-Cryptography Theory
2
+
3
+ ## Why "use the modern primitive" is the rule
4
+
5
+ Cryptographic primitives have a known break timeline. MD5 was
6
+ broken in 2004 (collisions in seconds on commodity hardware).
7
+ SHA-1 was broken in 2017 (shattered.io collision). DES has been
8
+ brute-forceable on dedicated hardware since the 1990s. ECB was
9
+ demonstrably insecure since the moment it was first analyzed.
10
+
11
+ Once a primitive is broken, two things follow:
12
+
13
+ 1. **Attacks improve over time, never get worse.** Collision-finding
14
+ complexity for MD5 went from 2^64 (theoretical, 2004) to 2^16
15
+ (chosen-prefix collisions, 2010s) to "instant on a laptop"
16
+ (multi-collision tools today).
17
+
18
+ 2. **Migration becomes free.** Every modern library has the
19
+ replacement primitive available. There's no engineering cost to
20
+ using SHA-256 instead of MD5; both are one library call.
21
+
22
+ The fix is universally available. The only reason these
23
+ primitives still appear in source is operator inertia.
24
+
25
+ ## Per-primitive break status
26
+
27
+ ### MD5
28
+
29
+ Collision attacks are trivial. Length-extension attacks predate
30
+ SHA-2. Practical break in any security context: signing, integrity
31
+ verification against adversaries, password hashing.
32
+
33
+ OK uses: content-addressable storage where collisions only need to
34
+ be unlikely against benign input (not adversarial), checksums in
35
+ non-security protocols, debugging hashes.
36
+
37
+ Use SHA-256 (still no practical attacks) or BLAKE2b / SHA-3 (newer
38
+ primitives) instead.
39
+
40
+ ### SHA-1
41
+
42
+ Shattered.io (2017) demonstrated chosen-prefix collisions. SHA-1
43
+ should be considered broken for all security uses.
44
+
45
+ OK uses: same as MD5 — non-security checksums.
46
+
47
+ Migrate to SHA-256.
48
+
49
+ ### DES / 3DES
50
+
51
+ DES is brute-forceable on commodity hardware (effective key size:
52
+ 56 bits). 3DES is computationally feasible to break with
53
+ billion-block plaintext (Sweet32 attack against 64-bit block size).
54
+ NIST disallowed 3DES for new applications in 2017.
55
+
56
+ Migrate to AES-256-GCM. Same library, different constructor.
57
+
58
+ ### RC4
59
+
60
+ Multiple statistical biases in keystream make plaintext recovery
61
+ practical given enough ciphertext. Deprecated by RFC 7465 (2015).
62
+
63
+ Migrate to AES-GCM or ChaCha20-Poly1305.
64
+
65
+ ### AES-ECB
66
+
67
+ Electronic Codebook mode encrypts each block independently with
68
+ the same key. Identical plaintext blocks produce identical
69
+ ciphertext blocks. The structure of the plaintext leaks through
70
+ the ciphertext (the canonical "ECB penguin" image demonstration).
71
+
72
+ Migrate to AES-GCM (authenticated encryption, single primitive),
73
+ or AES-CBC + HMAC-SHA-256 (encrypt-then-MAC pattern). GCM is
74
+ preferred for new code.
75
+
76
+ ### Hardcoded IVs
77
+
78
+ CBC mode and CTR mode both require a random IV per encryption.
79
+ Reusing an IV with the same key:
80
+
81
+ - CBC: leaks whether two plaintexts share a prefix
82
+ - CTR: leaks the XOR of the two plaintexts (catastrophic)
83
+ - GCM: REPEATED IV BREAKS THE CIPHER — attacker can recover the
84
+ authentication key
85
+
86
+ Generate a fresh random IV per encryption. Store the IV alongside
87
+ the ciphertext; it's not secret, but it must be unique-per-key.
88
+
89
+ ### Custom XOR loops
90
+
91
+ The classic "I'll write my own crypto" trap. XOR-based "encryption"
92
+ with a repeating key is the Vigenère cipher with shorter alphabet;
93
+ breakable by frequency analysis with enough ciphertext.
94
+
95
+ There is no legitimate use case for hand-rolled crypto in 2026.
96
+ Use the language's library.
97
+
98
+ ### Non-crypto random
99
+
100
+ `Math.random()` (JS), `random.random()` (Python without `secrets`
101
+ module), `java.util.Random` (Java), `math/rand` (Go), `rand()` /
102
+ `mt_rand()` (PHP), `new Random()` (.NET) all use deterministic
103
+ pseudo-random generators with predictable output given a small
104
+ amount of observed state.
105
+
106
+ Using these to generate:
107
+
108
+ - Session tokens → attacker predicts future tokens from one observed token
109
+ - Password reset tokens → attacker requests a reset on victim, predicts the token
110
+ - Encryption keys / IVs → attacker recreates the key from minimal observation
111
+ - CSRF tokens → attacker predicts a valid token
112
+
113
+ The fix: use the crypto-grade random API.
114
+
115
+ | Language | Crypto random |
116
+ |---|---|
117
+ | Python | `secrets.token_bytes(n)`, `secrets.token_urlsafe(n)` |
118
+ | Node | `crypto.randomBytes(n)`, `crypto.randomUUID()` |
119
+ | Java | `java.security.SecureRandom` |
120
+ | Go | `crypto/rand` (NOT `math/rand`) |
121
+ | PHP | `random_bytes(n)` |
122
+ | .NET | `RandomNumberGenerator.Create()` |
123
+ | Ruby | `SecureRandom.bytes(n)`, `SecureRandom.hex(n)` |
124
+ | Rust | `rand::thread_rng()` is NOT crypto-safe; use `rand::rngs::OsRng` or `getrandom` |
125
+
126
+ ### Disabled certificate verification
127
+
128
+ `verify=False` (Python requests), `rejectUnauthorized: false`
129
+ (Node), `InsecureSkipVerify: true` (Go), custom-trust-everything
130
+ `X509TrustManager` (Java), `ServerCertificateValidationCallback`
131
+ returning true (.NET).
132
+
133
+ All of these turn HTTPS into HTTP — a network attacker can MITM
134
+ without the application noticing. There are roughly zero
135
+ legitimate production use cases for these flags.
136
+
137
+ The legitimate development use cases (testing against a self-
138
+ signed cert):
139
+
140
+ - Install the dev cert in the OS trust store (one-time setup)
141
+ - Use a tool like mkcert to generate a locally-trusted cert
142
+ - For ephemeral test environments, use a dedicated test CA
143
+
144
+ Production code with `verify=False` is a failure of the upstream
145
+ ops team to provision proper TLS, hardcoded as an application
146
+ choice. Fix the TLS setup, not the verification flag.
147
+
148
+ ### Password hashing
149
+
150
+ `hashlib.sha256(password)` is a general-purpose hash function.
151
+ It's:
152
+
153
+ - Fast (designed to be fast — bad for password hashing)
154
+ - Unsalted by default (vulnerable to rainbow-table attacks)
155
+ - Single-iteration (no work factor — no way to slow down brute force)
156
+
157
+ Modern password hashing uses purpose-built KDFs:
158
+
159
+ - **bcrypt** — 1999, widely supported, decent
160
+ - **scrypt** — 2009, memory-hard (resistant to GPU/ASIC)
161
+ - **argon2id** — 2015, current PHC-recommended
162
+
163
+ All three have configurable work factors that tune to your hardware
164
+ and user-acceptable login latency. They incorporate salts
165
+ automatically; the salt is stored alongside the hash.
166
+
167
+ Modern recommendation: argon2id. Acceptable fallback: bcrypt with
168
+ cost factor ≥ 12.
169
+
170
+ ## Why static-pattern scanning misses some weak crypto
171
+
172
+ This scanner detects API-level misuse. Some weaknesses require
173
+ deeper analysis:
174
+
175
+ - Custom protocol design errors (e.g., using a hash where a MAC
176
+ is required) require semantic analysis the scanner can't do
177
+ - Insufficient key sizes (RSA-1024, etc.) detected via library
178
+ API form (`RSA.generate(1024)`) but not always
179
+ - Padding-oracle vulnerabilities in CBC mode require behavioral
180
+ testing, not static analysis
181
+
182
+ Treat the scanner as the obvious-cases pass. A full crypto audit
183
+ needs domain expertise + tools like Semgrep + cryptography-
184
+ specific reviewers.
185
+
186
+ ## Primary sources
187
+
188
+ - [CWE-327 Use of Broken Cryptographic Algorithm](https://cwe.mitre.org/data/definitions/327.html)
189
+ - [CWE-330 Use of Insufficiently Random Values](https://cwe.mitre.org/data/definitions/330.html)
190
+ - [CWE-916 Insufficient Computational Effort](https://cwe.mitre.org/data/definitions/916.html)
191
+ - [CWE-295 Improper Certificate Validation](https://cwe.mitre.org/data/definitions/295.html)
192
+ - [NIST SP 800-131A Transitions of Cryptographic Algorithms](https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final)
193
+ - [OWASP Cryptographic Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html)
194
+ - [Password Hashing Competition (PHC) — argon2 winner](https://www.password-hashing.net/)