@runsec/mcp 1.0.1

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 (40) hide show
  1. package/dist/index.js +578 -0
  2. package/package.json +43 -0
  3. package/src/rules/data/rule-compliance-map.json +43563 -0
  4. package/src/rules/data/semgrep-rules/README-taint-overlays.md +21 -0
  5. package/src/rules/data/semgrep-rules/advanced-agent-cloud.yaml +802 -0
  6. package/src/rules/data/semgrep-rules/app-logic.yaml +445 -0
  7. package/src/rules/data/semgrep-rules/auth-keycloak.yaml +831 -0
  8. package/src/rules/data/semgrep-rules/browser-agent.yaml +260 -0
  9. package/src/rules/data/semgrep-rules/cloud-secrets.yaml +316 -0
  10. package/src/rules/data/semgrep-rules/csharp-dotnet.yaml +4864 -0
  11. package/src/rules/data/semgrep-rules/desktop-electron-pro.yaml +30 -0
  12. package/src/rules/data/semgrep-rules/desktop-vsto-suite.yaml +2759 -0
  13. package/src/rules/data/semgrep-rules/devops-security.yaml +393 -0
  14. package/src/rules/data/semgrep-rules/domain-access-management.yaml +1023 -0
  15. package/src/rules/data/semgrep-rules/domain-data-privacy.yaml +852 -0
  16. package/src/rules/data/semgrep-rules/domain-input-validation.yaml +2894 -0
  17. package/src/rules/data/semgrep-rules/domain-platform-hardening.yaml +1715 -0
  18. package/src/rules/data/semgrep-rules/ds-ml-security.yaml +2431 -0
  19. package/src/rules/data/semgrep-rules/fastapi-async.yaml +5953 -0
  20. package/src/rules/data/semgrep-rules/frontend-react.yaml +4035 -0
  21. package/src/rules/data/semgrep-rules/frontend-security.yaml +200 -0
  22. package/src/rules/data/semgrep-rules/go-core.yaml +4959 -0
  23. package/src/rules/data/semgrep-rules/hft-cpp-security.yaml +631 -0
  24. package/src/rules/data/semgrep-rules/infra-k8s-helm.yaml +4968 -0
  25. package/src/rules/data/semgrep-rules/integration-security.yaml +2362 -0
  26. package/src/rules/data/semgrep-rules/java-enterprise.yaml +14756 -0
  27. package/src/rules/data/semgrep-rules/java-spring.yaml +397 -0
  28. package/src/rules/data/semgrep-rules/license-compliance.yaml +186 -0
  29. package/src/rules/data/semgrep-rules/mobile-flutter.yaml +37 -0
  30. package/src/rules/data/semgrep-rules/mobile-security.yaml +721 -0
  31. package/src/rules/data/semgrep-rules/nodejs-nestjs.yaml +5164 -0
  32. package/src/rules/data/semgrep-rules/nodejs-security.yaml +326 -0
  33. package/src/rules/data/semgrep-rules/observability.yaml +381 -0
  34. package/src/rules/data/semgrep-rules/php-security.yaml +3601 -0
  35. package/src/rules/data/semgrep-rules/python-backend-pro.yaml +30 -0
  36. package/src/rules/data/semgrep-rules/python-django.yaml +181 -0
  37. package/src/rules/data/semgrep-rules/python-security.yaml +284 -0
  38. package/src/rules/data/semgrep-rules/ru-regulatory.yaml +496 -0
  39. package/src/rules/data/semgrep-rules/ruby-rails.yaml +3078 -0
  40. package/src/rules/data/semgrep-rules/rust-security.yaml +2701 -0
@@ -0,0 +1,831 @@
1
+ rules:
2
+ - id: runsec.auth-keycloak.ak-001
3
+ metadata:
4
+ runsec_version: v1.0
5
+ confidence: |-
6
+ 0.9
7
+ exploit_scenario: |-
8
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
9
+ fix_template: |-
10
+ from jose import jwt header = jwt.get_unverified_header(token) if header.get(\"alg\") not in {\"RS256\", \"ES256\", \"GOST3410\"}: raise ValueError(\"unsupported alg\") claims = jwt.decode( token, jwk, algorithms=[\"RS256\", \"ES256\", \"GOST3410\"], issuer=issuer_url, audience=client_id, options={\"verify_signature\": True}, ) # для контура Клинкера включить профиль российских криптоалгоритмов (ГОСТ)
11
+ pattern-either:
12
+ - pattern: |-
13
+ from jose import jwt
14
+ claims = jwt.decode(token, key="", algorithms=["none"])
15
+ # либо library defaults без allowlist alg
16
+ - pattern-regex: 'Vulnerable:\\s*AK\\-001\\b'
17
+ message: |-
18
+ RunSec Detection [AK-001]: Auth0 JWT Handbook, Validate JSON Web Tokens > Manually implement checks (disallow none)
19
+ languages:
20
+ - python
21
+ severity: WARNING
22
+ - id: runsec.auth-keycloak.ak-002
23
+ metadata:
24
+ runsec_version: v1.0
25
+ confidence: |-
26
+ 0.9
27
+ exploit_scenario: |-
28
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
29
+ fix_template: |-
30
+ import jwt claims = jwt.decode( token, pub_key, algorithms=[\"RS256\", \"ES256\"], issuer=issuer_url, audience=client_id, options={\"verify_signature\": True, \"verify_exp\": True, \"verify_nbf\": True, \"verify_iat\": True}, )
31
+ pattern-either:
32
+ - pattern: |-
33
+ import jwt
34
+ claims = jwt.decode(token, pub_key, algorithms=["RS256"], options={"verify_signature": True, "verify_exp": True})
35
+ - pattern-regex: 'Vulnerable:\\s*AK\\-002\\b'
36
+ message: |-
37
+ RunSec Detection [AK-002]: Auth0 JWT Handbook, Validate JSON Web Tokens > Issuer Validation + Audience Validation
38
+ languages:
39
+ - python
40
+ severity: WARNING
41
+ - id: runsec.auth-keycloak.ak-003
42
+ metadata:
43
+ runsec_version: v1.0
44
+ confidence: |-
45
+ 0.9
46
+ exploit_scenario: |-
47
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
48
+ fix_template: |-
49
+ header = jwt.get_unverified_header(token) kid = header.get(\"kid\") trusted_kids = {k[\"kid\"] for k in jwks[\"keys\"]} if kid not in trusted_kids: raise ValueError(\"untrusted kid\") jwk = next(k for k in jwks[\"keys\"] if k[\"kid\"] == kid) claims = jwt.decode(token, jwk, algorithms=[\"RS256\", \"ES256\"], issuer=issuer_url, audience=client_id)
50
+ pattern-either:
51
+ - pattern: |-
52
+ header = jwt.get_unverified_header(token)
53
+ jwk = jwks[header["kid"]]
54
+ claims = jwt.decode(token, jwk, algorithms=["RS256"])
55
+ - pattern-regex: 'Vulnerable:\\s*AK\\-003\\b'
56
+ message: |-
57
+ RunSec Detection [AK-003]: Auth0 JWT Handbook, Validate JSON Web Tokens > Key ID (kid) Header and JWKS Matching
58
+ languages:
59
+ - python
60
+ severity: WARNING
61
+ - id: runsec.auth-keycloak.ak-004
62
+ metadata:
63
+ runsec_version: v1.0
64
+ confidence: |-
65
+ 0.9
66
+ exploit_scenario: |-
67
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
68
+ fix_template: |-
69
+ allowed_redirects = { \"https://app.example.com/oidc/callback\", \"https://admin.example.com/oidc/callback\", } if redirect_uri not in allowed_redirects: raise ValueError(\"redirect_uri mismatch\")
70
+ pattern-either:
71
+ - pattern: |-
72
+ allowed_redirects = ["https://app.example.com/*", "http://localhost/*"]
73
+ if redirect_uri.startswith("https://app.example.com/"):
74
+ pass
75
+ - pattern-regex: 'Vulnerable:\\s*AK\\-004\\b'
76
+ message: |-
77
+ RunSec Detection [AK-004]: RFC 6819, section 5.2.3.5
78
+ languages:
79
+ - python
80
+ severity: WARNING
81
+ - id: runsec.auth-keycloak.ak-005
82
+ metadata:
83
+ runsec_version: v1.0
84
+ confidence: |-
85
+ 0.9
86
+ exploit_scenario: |-
87
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
88
+ fix_template: |-
89
+ import os from keycloak import KeycloakOpenID kc = KeycloakOpenID( server_url=os.environ[\"KEYCLOAK_URL\"], realm_name=os.environ[\"KEYCLOAK_REALM\"], client_id=os.environ[\"KEYCLOAK_CLIENT_ID\"], client_secret_key=os.environ[\"KEYCLOAK_CLIENT_SECRET\"], )
90
+ pattern-either:
91
+ - pattern: |-
92
+ from keycloak import KeycloakOpenID
93
+ kc = KeycloakOpenID(
94
+ server_url="https://id.example.com",
95
+ realm_name="prod",
96
+ client_id="backend",
97
+ client_secret_key="hardcoded-secret",
98
+ )
99
+ - pattern-regex: 'Vulnerable:\\s*AK\\-005\\b'
100
+ message: |-
101
+ RunSec Detection [AK-005]: RFC 6819, section 5.2.3.6; OAuth 2.0 (RFC 6749), section 10.1
102
+ languages:
103
+ - python
104
+ severity: WARNING
105
+ - id: runsec.auth-keycloak.ak-006
106
+ metadata:
107
+ runsec_version: v1.0
108
+ confidence: |-
109
+ 0.9
110
+ exploit_scenario: |-
111
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
112
+ fix_template: |-
113
+ claims = jwt.decode(token, jwk, algorithms=[\"RS256\", \"ES256\"], issuer=issuer_url, audience=client_id, options={\"verify_exp\": True, \"verify_nbf\": True, \"verify_iat\": True}) user = db.get_user_by_id(current_user_id) if claims.get(\"sub\") != user.oidc_sub: raise ValueError(\"subject mismatch\")
114
+ pattern-either:
115
+ - pattern: |-
116
+ claims = jwt.decode(token, jwk, algorithms=["RS256"], issuer=issuer_url, audience=client_id)
117
+ user = db.get_user_by_email(claims.get("email"))
118
+ # sub не проверяется
119
+ - pattern-regex: 'Vulnerable:\\s*AK\\-006\\b'
120
+ message: |-
121
+ RunSec Detection [AK-006]: Auth0 JWT Handbook, Validate JSON Web Tokens > Validate claims
122
+ languages:
123
+ - python
124
+ severity: WARNING
125
+ - id: runsec.auth-keycloak.ak-007
126
+ metadata:
127
+ runsec_version: v1.0
128
+ confidence: |-
129
+ 0.9
130
+ exploit_scenario: |-
131
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
132
+ fix_template: |-
133
+ assert request_client_id == stored_client_id_for_code(code) assert request_redirect_uri == stored_redirect_uri_for_code(code) token = exchange_code_for_token(code=code, client_id=request_client_id, redirect_uri=request_redirect_uri)
134
+ pattern-either:
135
+ - pattern: |-
136
+ token = exchange_code_for_token(code=code, client_id=client_id)
137
+ - pattern-regex: 'Vulnerable:\\s*AK\\-007\\b'
138
+ message: |-
139
+ RunSec Detection [AK-007]: RFC 6819, section 5.2.4.5
140
+ languages:
141
+ - python
142
+ severity: WARNING
143
+ - id: runsec.auth-keycloak.ak-008
144
+ metadata:
145
+ runsec_version: v1.0
146
+ confidence: |-
147
+ 0.9
148
+ exploit_scenario: |-
149
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
150
+ fix_template: |-
151
+ claims = jwt.decode(token, jwk, algorithms=[\"RS256\", \"ES256\"], issuer=issuer_url, audience=client_id, options={\"verify_exp\": True, \"verify_nbf\": True, \"verify_iat\": True})
152
+ pattern-either:
153
+ - pattern: |-
154
+ claims = jwt.decode(token, jwk, algorithms=["RS256"], issuer=issuer_url, audience=client_id, options={"verify_exp": False, "verify_nbf": False, "verify_iat": False})
155
+ - pattern-regex: 'Vulnerable:\\s*AK\\-008\\b'
156
+ message: |-
157
+ RunSec Detection [AK-008]: Auth0 JWT Handbook, Validate JSON Web Tokens > JWT validation checks structure, claims, and signature
158
+ languages:
159
+ - python
160
+ severity: WARNING
161
+ - id: runsec.auth-keycloak.ak-009
162
+ metadata:
163
+ runsec_version: v1.0
164
+ confidence: |-
165
+ 0.9
166
+ exploit_scenario: |-
167
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
168
+ fix_template: |-
169
+ auth_url = f"{issuer}/protocol/openid-connect/auth?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&code_challenge={code_challenge}&code_challenge_method=S256" token = exchange_code(code=code, code_verifier=code_verifier) if not code_verifier: raise ValueError("pkce required")
170
+ pattern-either:
171
+ - pattern: |-
172
+ auth_url = f"{issuer}/protocol/openid-connect/auth?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}"
173
+ # token exchange without code_verifier
174
+ token = exchange_code(code=code)
175
+ - pattern-regex: 'Vulnerable:\\s*AK\\-009\\b'
176
+ message: |-
177
+ RunSec Detection [AK-009]: FAPI 2.0 Security Profile; ГОСТ 57580.1 (IA); OAuth 2.1 Draft; OWASP ASVS v4.0.3
178
+ languages:
179
+ - python
180
+ severity: WARNING
181
+ - id: runsec.auth-keycloak.ak-010
182
+ metadata:
183
+ runsec_version: v1.0
184
+ confidence: |-
185
+ 0.9
186
+ exploit_scenario: |-
187
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
188
+ fix_template: |-
189
+ def call_high_risk_api(access_token: str, dpop_proof: str): if not dpop_proof: raise ValueError("DPoP proof required") return client.post("/payments/transfer", headers={"Authorization": f"Bearer {access_token}", "DPoP": dpop_proof}) # DPoP обязателен для высокорисковых операций ЦБ, чтобы снизить риск кражи токенов
190
+ pattern-either:
191
+ - pattern: |-
192
+ def call_high_risk_api(access_token: str):
193
+ return client.post("/payments/transfer", headers={"Authorization": f"Bearer {access_token}"})
194
+ - pattern-regex: 'Vulnerable:\\s*AK\\-010\\b'
195
+ message: |-
196
+ RunSec Detection [AK-010]: FAPI 2.0 Security Profile; OAuth 2.1 Draft; OWASP ASVS v4.0.3
197
+ languages:
198
+ - python
199
+ severity: WARNING
200
+ - id: runsec.auth-keycloak.ak-011
201
+ metadata:
202
+ runsec_version: v1.0
203
+ confidence: |-
204
+ 0.9
205
+ exploit_scenario: |-
206
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
207
+ fix_template: |-
208
+ payload = {"sub": user_id, "role": role, "scope": "api.read"} token = jwt.encode(payload, private_key, algorithm="RS256") # PII moved to userinfo endpoint or encrypted storage
209
+ pattern-either:
210
+ - pattern: |-
211
+ payload = {"sub": user_id, "email": email, "phone": phone, "name": full_name, "role": role}
212
+ token = jwt.encode(payload, private_key, algorithm="RS256")
213
+ - pattern-regex: 'Vulnerable:\\s*AK\\-011\\b'
214
+ message: |-
215
+ RunSec Detection [AK-011]: OAuth 2.1 Draft; OWASP ASVS v4.0.3
216
+ languages:
217
+ - python
218
+ severity: WARNING
219
+ - id: runsec.auth-keycloak.ak-012
220
+ metadata:
221
+ runsec_version: v1.0
222
+ confidence: |-
223
+ 0.9
224
+ exploit_scenario: |-
225
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
226
+ fix_template: |-
227
+ def get_jwk_for_kid(kid: str): if kid in negative_kid_cache and not negative_kid_cache[kid].expired: raise ValueError("unknown kid cached") if not jwks_rate_limiter.allow("jwks_fetch"): raise RuntimeError("jwks rate limit exceeded") jwks = requests.get(f"{issuer}/.well-known/jwks.json", timeout=2).json() # cache keys and unknown kid misses return select_key_from_jwks(jwks, kid)
228
+ pattern-either:
229
+ - pattern: |-
230
+ def get_jwk_for_kid(kid: str):
231
+ # every unknown kid triggers upstream call
232
+ return requests.get(f"{issuer}/.well-known/jwks.json", timeout=2).json()
233
+ - pattern-regex: 'Vulnerable:\\s*AK\\-012\\b'
234
+ message: |-
235
+ RunSec Detection [AK-012]: OAuth 2.1 Draft; OWASP ASVS v4.0.3
236
+ languages:
237
+ - python
238
+ severity: WARNING
239
+ - id: runsec.auth-keycloak.ak-013
240
+ metadata:
241
+ runsec_version: v1.0
242
+ confidence: |-
243
+ 0.9
244
+ exploit_scenario: |-
245
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
246
+ fix_template: |-
247
+ def exchange_token(user_jwt: str, audience: str) -> str: resp = requests.post(f"{issuer}/protocol/openid-connect/token", data={ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": user_jwt, "subject_token_type": "urn:ietf:params:oauth:token-type:access_token", "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", "audience": audience, }, auth=(client_id, client_secret), cert=(client_cert_path, client_key_path), timeout=5) resp.raise_for_status() return resp.json()["access_token"] def call_internal_service(user_jwt: str): svc_token = exchange_token(user_jwt, audience="orders-api") return requests.get("http://orders.internal/api/orders", headers={"Authorization": f"Bearer {svc_token}"}, timeout=5) # token exchange endpoint /token вызывать только по mTLS в профиле ФАПИ.ПАОК
248
+ pattern-either:
249
+ - pattern: |-
250
+ def call_internal_service(user_jwt: str):
251
+ return requests.get("http://orders.internal/api/orders", headers={"Authorization": f"Bearer {user_jwt}"})
252
+ - pattern-regex: 'Vulnerable:\\s*AK\\-013\\b'
253
+ message: |-
254
+ RunSec Detection [AK-013]: RFC 8693; FAPI 2.0 Security Profile
255
+ languages:
256
+ - python
257
+ severity: WARNING
258
+ - id: runsec.auth-keycloak.ak-014
259
+ metadata:
260
+ runsec_version: v1.0
261
+ confidence: |-
262
+ 0.9
263
+ exploit_scenario: |-
264
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
265
+ fix_template: |-
266
+ token_req = { "grant_type": "authorization_code", "code": code, "redirect_uri": redirect_uri, "resource": "https://api.example.com/orders", } token = requests.post(token_url, data=token_req, auth=(client_id, client_secret), timeout=5) token.raise_for_status()
267
+ pattern-either:
268
+ - pattern: |-
269
+ token_req = {
270
+ "grant_type": "authorization_code",
271
+ "code": code,
272
+ "redirect_uri": redirect_uri,
273
+ }
274
+ token = requests.post(token_url, data=token_req, auth=(client_id, client_secret), timeout=5)
275
+ - pattern-regex: 'Vulnerable:\\s*AK\\-014\\b'
276
+ message: |-
277
+ RunSec Detection [AK-014]: RFC 8707; FAPI 2.0 Security Profile
278
+ languages:
279
+ - python
280
+ severity: WARNING
281
+ - id: runsec.auth-keycloak.ak-015
282
+ metadata:
283
+ runsec_version: v1.0
284
+ confidence: |-
285
+ 0.9
286
+ exploit_scenario: |-
287
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
288
+ fix_template: |-
289
+ @app.get("/oidc/callback") async def callback(code: str, state: str, request: Request): expected = request.session.get("oidc_state") if not expected or state != expected: raise HTTPException(status_code=401, detail="invalid state") ... return await exchange_code(code)
290
+ pattern-either:
291
+ - pattern: |-
292
+ @app.get("/oidc/callback")
293
+ async def callback(code: str, state: str):
294
+ ...
295
+ return await exchange_code(code)
296
+ - pattern-regex: 'Vulnerable:\\s*AK\\-015\\b'
297
+ message: |-
298
+ RunSec Detection [AK-015]: CWE-384
299
+ languages:
300
+ - python
301
+ severity: WARNING
302
+ - id: runsec.auth-keycloak.ak-016
303
+ metadata:
304
+ runsec_version: v1.0
305
+ confidence: |-
306
+ 0.9
307
+ exploit_scenario: |-
308
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
309
+ fix_template: |-
310
+ id_claims = jwt.decode(id_token, jwk, algorithms=["RS256","ES256"], audience=client_id, issuer=issuer) expected_nonce = request.session.get("oidc_nonce") if not expected_nonce or id_claims.get("nonce") != expected_nonce: raise HTTPException(status_code=401, detail="invalid nonce") ... return id_claims
311
+ pattern-either:
312
+ - pattern: |-
313
+ id_claims = jwt.decode(id_token, jwk, algorithms=["RS256"], audience=client_id, issuer=issuer)
314
+ ...
315
+ return id_claims
316
+ - pattern-regex: 'Vulnerable:\\s*AK\\-016\\b'
317
+ message: |-
318
+ RunSec Detection [AK-016]: CWE-346
319
+ languages:
320
+ - python
321
+ severity: WARNING
322
+ - id: runsec.auth-keycloak.ak-017
323
+ metadata:
324
+ runsec_version: v1.0
325
+ confidence: |-
326
+ 0.9
327
+ exploit_scenario: |-
328
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
329
+ fix_template: |-
330
+ refresh_token_ttl = 86400 if refresh_token_ttl > 86400: raise ValueError("CB session limit exceeded") enable_backchannel_logout = True enable_frontchannel_logout = True revoke_refresh_token_on_logout = True
331
+ pattern-either:
332
+ - pattern: |-
333
+ refresh_token_ttl = 864000
334
+ # no back-channel/front-channel logout
335
+ - pattern-regex: 'Vulnerable:\\s*AK\\-017\\b'
336
+ message: |-
337
+ RunSec Detection [AK-017]: ГОСТ 57580.1 (IA); требования ЦБ по управлению сессиями
338
+ languages:
339
+ - python
340
+ severity: WARNING
341
+ - id: runsec.auth-keycloak.ak-018
342
+ metadata:
343
+ runsec_version: v1.0
344
+ confidence: |-
345
+ 0.9
346
+ exploit_scenario: |-
347
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
348
+ fix_template: |-
349
+ Все межсервисные вызовы выполнять по mTLS (service identity, cert pinning, trust policy), не только token exchange endpoint.
350
+ pattern-either:
351
+ - pattern: |-
352
+ requests.get("http://orders.internal/api")
353
+ grpc.insecure_channel("billing.internal:50051")
354
+ - pattern-regex: 'Vulnerable:\\s*AK\\-018\\b'
355
+ message: |-
356
+ RunSec Detection [AK-018]: NIST SP 800-207 (Zero Trust)
357
+ languages:
358
+ - python
359
+ severity: WARNING
360
+ - id: runsec.auth-keycloak.ak-019
361
+ metadata:
362
+ runsec_version: v1.0
363
+ confidence: |-
364
+ 0.9
365
+ exploit_scenario: |-
366
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
367
+ fix_template: |-
368
+ Для админ-учетных записей принудительная ротация клиентских секретов, короткий TTL сессий, step-up auth и немедленный revoke при logout/risk events.
369
+ pattern-either:
370
+ - pattern: |-
371
+ admin_session_ttl = 7*24*3600
372
+ admin_client_secret = "static-secret"
373
+ - pattern-regex: 'Vulnerable:\\s*AK\\-019\\b'
374
+ message: |-
375
+ RunSec Detection [AK-019]: OWASP ASVS v4.0 (L3), NIST 800-63
376
+ languages:
377
+ - python
378
+ severity: WARNING
379
+ - id: runsec.auth-keycloak.ak-020
380
+ metadata:
381
+ runsec_version: v1.0
382
+ confidence: |-
383
+ 0.9
384
+ exploit_scenario: |-
385
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
386
+ fix_template: |-
387
+ Никогда не отключать проверку подписи; валидировать подпись JWT по JWKS и reject токены с invalid signature.
388
+ pattern-either:
389
+ - pattern: |-
390
+ jwt.decode(token, key, options={"verify_signature": False})
391
+ - pattern-regex: 'Vulnerable:\\s*AK\\-020\\b'
392
+ message: |-
393
+ RunSec Detection [AK-020]: CWE Final Certification
394
+ languages:
395
+ - python
396
+ severity: WARNING
397
+ - id: runsec.auth-keycloak.ak-021
398
+ metadata:
399
+ runsec_version: v1.0
400
+ confidence: |-
401
+ 0.9
402
+ exploit_scenario: |-
403
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
404
+ fix_template: |-
405
+ Всегда указывать algorithms=["RS256"] (или строгий allowlist) и запрещать algorithm confusion/fallback.
406
+ pattern-either:
407
+ - pattern: |-
408
+ jwt.decode(token, key, audience=aud, issuer=iss)
409
+ - pattern-regex: 'Vulnerable:\\s*AK\\-021\\b'
410
+ message: |-
411
+ RunSec Detection [AK-021]: CWE Final Certification
412
+ languages:
413
+ - python
414
+ severity: WARNING
415
+ - id: runsec.auth-keycloak.ak-022
416
+ metadata:
417
+ runsec_version: v1.0
418
+ confidence: |-
419
+ 0.9
420
+ exploit_scenario: |-
421
+ N/A
422
+ fix_template: |-
423
+ Rotate session identifiers after authentication.
424
+ pattern-either:
425
+ - pattern: |-
426
+ session.setAttribute("uid", uid)
427
+ - pattern-regex: 'Vulnerable:\\s*AK\\-022\\b'
428
+ message: |-
429
+ RunSec Detection [AK-022]: CWE-384
430
+ languages:
431
+ - python
432
+ severity: WARNING
433
+ - id: runsec.auth-keycloak.ak-023
434
+ metadata:
435
+ runsec_version: v1.0
436
+ confidence: |-
437
+ 0.9
438
+ exploit_scenario: |-
439
+ N/A
440
+ fix_template: |-
441
+ Split pre-auth and post-auth cookie scopes.
442
+ pattern-either:
443
+ - pattern: |-
444
+ sid = request.cookies.get("AUTH_SESSION_ID")
445
+ response.set_cookie("AUTH_SESSION_ID", sid)
446
+ - pattern-regex: 'Vulnerable:\\s*AK\\-023\\b'
447
+ message: |-
448
+ RunSec Detection [AK-023]: CWE-384
449
+ languages:
450
+ - python
451
+ severity: WARNING
452
+ - id: runsec.auth-keycloak.ak-024
453
+ metadata:
454
+ runsec_version: v1.0
455
+ confidence: |-
456
+ 0.9
457
+ exploit_scenario: |-
458
+ N/A
459
+ fix_template: |-
460
+ Enforce immediate refresh revocation.
461
+ pattern-either:
462
+ - pattern: |-
463
+ def logout(rt): pass # no revoke
464
+ - pattern-regex: 'Vulnerable:\\s*AK\\-024\\b'
465
+ message: |-
466
+ RunSec Detection [AK-024]: CWE-613
467
+ languages:
468
+ - python
469
+ severity: WARNING
470
+ - id: runsec.auth-keycloak.ak-025
471
+ metadata:
472
+ runsec_version: v1.0
473
+ confidence: |-
474
+ 0.9
475
+ exploit_scenario: |-
476
+ N/A
477
+ fix_template: |-
478
+ Bind refresh lifecycle to one-time use.
479
+ pattern-either:
480
+ - pattern: |-
481
+ if validate(old_rt) or validate(new_rt): issue_token()
482
+ - pattern-regex: 'Vulnerable:\\s*AK\\-025\\b'
483
+ message: |-
484
+ RunSec Detection [AK-025]: CWE-294
485
+ languages:
486
+ - python
487
+ severity: WARNING
488
+ - id: runsec.auth-keycloak.ak-026
489
+ metadata:
490
+ runsec_version: v1.0
491
+ confidence: |-
492
+ 0.9
493
+ exploit_scenario: |-
494
+ N/A
495
+ fix_template: |-
496
+ Add contextual token binding.
497
+ pattern-either:
498
+ - pattern: |-
499
+ token = sign({"u": username})
500
+ - pattern-regex: 'Vulnerable:\\s*AK\\-026\\b'
501
+ message: |-
502
+ RunSec Detection [AK-026]: CWE-384
503
+ languages:
504
+ - python
505
+ severity: WARNING
506
+ - id: runsec.auth-keycloak.ak-027
507
+ metadata:
508
+ runsec_version: v1.0
509
+ confidence: |-
510
+ 0.9
511
+ exploit_scenario: |-
512
+ N/A
513
+ fix_template: |-
514
+ Cap absolute SSO session TTL.
515
+ pattern-either:
516
+ - pattern: |-
517
+ session.expires_at = now + idle_ttl # forever
518
+ - pattern-regex: 'Vulnerable:\\s*AK\\-027\\b'
519
+ message: |-
520
+ RunSec Detection [AK-027]: CWE-613
521
+ languages:
522
+ - python
523
+ severity: WARNING
524
+ - id: runsec.auth-keycloak.ak-028
525
+ metadata:
526
+ runsec_version: v1.0
527
+ confidence: |-
528
+ 0.9
529
+ exploit_scenario: |-
530
+ N/A
531
+ fix_template: |-
532
+ Server controls all session identifiers.
533
+ pattern-either:
534
+ - pattern: |-
535
+ sid = request.cookies.get("JSESSIONID")
536
+ login_with_session(sid)
537
+ - pattern-regex: 'Vulnerable:\\s*AK\\-028\\b'
538
+ message: |-
539
+ RunSec Detection [AK-028]: CWE-384
540
+ languages:
541
+ - python
542
+ severity: WARNING
543
+ - id: runsec.auth-keycloak.ak-029
544
+ metadata:
545
+ runsec_version: v1.0
546
+ confidence: |-
547
+ 0.9
548
+ exploit_scenario: |-
549
+ N/A
550
+ fix_template: |-
551
+ Scope refreshed tokens per resource.
552
+ pattern-either:
553
+ - pattern: |-
554
+ token = refresh(rt) # no aud check
555
+ - pattern-regex: 'Vulnerable:\\s*AK\\-029\\b'
556
+ message: |-
557
+ RunSec Detection [AK-029]: CWE-345
558
+ languages:
559
+ - python
560
+ severity: WARNING
561
+ - id: runsec.auth-keycloak.ak-030
562
+ metadata:
563
+ runsec_version: v1.0
564
+ confidence: |-
565
+ 0.9
566
+ exploit_scenario: |-
567
+ N/A
568
+ fix_template: |-
569
+ Enforce single-session policy for privileged users.
570
+ pattern-either:
571
+ - pattern: |-
572
+ create_new_session(user)
573
+ - pattern-regex: 'Vulnerable:\\s*AK\\-030\\b'
574
+ message: |-
575
+ RunSec Detection [AK-030]: CWE-613
576
+ languages:
577
+ - python
578
+ severity: WARNING
579
+ - id: runsec.auth-keycloak.ak-031
580
+ metadata:
581
+ runsec_version: v1.0
582
+ confidence: |-
583
+ 0.9
584
+ exploit_scenario: |-
585
+ N/A
586
+ fix_template: |-
587
+ Bind refresh tokens to originating client.
588
+ pattern-either:
589
+ - pattern: |-
590
+ refresh(rt, client_id=req.client_id)
591
+ - pattern-regex: 'Vulnerable:\\s*AK\\-031\\b'
592
+ message: |-
593
+ RunSec Detection [AK-031]: CWE-290
594
+ languages:
595
+ - python
596
+ severity: WARNING
597
+ - id: runsec.auth-keycloak.ak-032
598
+ metadata:
599
+ runsec_version: v1.0
600
+ confidence: |-
601
+ 0.9
602
+ exploit_scenario: |-
603
+ N/A
604
+ fix_template: |-
605
+ Harden session cookies in all realms.
606
+ pattern-either:
607
+ - pattern: |-
608
+ set_cookie("SSO", sid)
609
+ - pattern-regex: 'Vulnerable:\\s*AK\\-032\\b'
610
+ message: |-
611
+ RunSec Detection [AK-032]: CWE-614
612
+ languages:
613
+ - python
614
+ severity: WARNING
615
+ - id: runsec.auth-keycloak.ak-033
616
+ metadata:
617
+ runsec_version: v1.0
618
+ confidence: |-
619
+ 0.9
620
+ exploit_scenario: |-
621
+ N/A
622
+ fix_template: |-
623
+ Reject replayed token identifiers.
624
+ pattern-either:
625
+ - pattern: |-
626
+ if validate(rt): issue_access()
627
+ - pattern-regex: 'Vulnerable:\\s*AK\\-033\\b'
628
+ message: |-
629
+ RunSec Detection [AK-033]: CWE-294
630
+ languages:
631
+ - python
632
+ severity: WARNING
633
+ - id: runsec.auth-keycloak.ak-034
634
+ metadata:
635
+ runsec_version: v1.0
636
+ confidence: |-
637
+ 0.9
638
+ exploit_scenario: |-
639
+ N/A
640
+ fix_template: |-
641
+ Isolate browser tab auth context.
642
+ pattern-either:
643
+ - pattern: |-
644
+ session["state"]=state
645
+ - pattern-regex: 'Vulnerable:\\s*AK\\-034\\b'
646
+ message: |-
647
+ RunSec Detection [AK-034]: CWE-384
648
+ languages:
649
+ - python
650
+ severity: WARNING
651
+ - id: runsec.auth-keycloak.ak-035
652
+ metadata:
653
+ runsec_version: v1.0
654
+ confidence: |-
655
+ 0.9
656
+ exploit_scenario: |-
657
+ N/A
658
+ fix_template: |-
659
+ Force re-authentication after password updates.
660
+ pattern-either:
661
+ - pattern: |-
662
+ change_password(user, pwd)
663
+ - pattern-regex: 'Vulnerable:\\s*AK\\-035\\b'
664
+ message: |-
665
+ RunSec Detection [AK-035]: CWE-613
666
+ languages:
667
+ - python
668
+ severity: WARNING
669
+ - id: runsec.auth-keycloak.ak-036
670
+ metadata:
671
+ runsec_version: v1.0
672
+ confidence: |-
673
+ 0.9
674
+ exploit_scenario: |-
675
+ N/A
676
+ fix_template: |-
677
+ Regenerate server session in broker flow.
678
+ pattern-either:
679
+ - pattern: |-
680
+ broker_callback(); login_success()
681
+ - pattern-regex: 'Vulnerable:\\s*AK\\-036\\b'
682
+ message: |-
683
+ RunSec Detection [AK-036]: CWE-384
684
+ languages:
685
+ - python
686
+ severity: WARNING
687
+ - id: runsec.auth-keycloak.ak-037
688
+ metadata:
689
+ runsec_version: v1.0
690
+ confidence: |-
691
+ 0.9
692
+ exploit_scenario: |-
693
+ N/A
694
+ fix_template: |-
695
+ Policy-gate offline token issuance.
696
+ pattern-either:
697
+ - pattern: |-
698
+ issue_offline_token(client)
699
+ - pattern-regex: 'Vulnerable:\\s*AK\\-037\\b'
700
+ message: |-
701
+ RunSec Detection [AK-037]: CWE-250
702
+ languages:
703
+ - python
704
+ severity: WARNING
705
+ - id: runsec.auth-keycloak.ak-038
706
+ metadata:
707
+ runsec_version: v1.0
708
+ confidence: |-
709
+ 0.9
710
+ exploit_scenario: |-
711
+ N/A
712
+ fix_template: |-
713
+ Normalize error and context behavior.
714
+ pattern-either:
715
+ - pattern: |-
716
+ return "user_not_found"
717
+ - pattern-regex: 'Vulnerable:\\s*AK\\-038\\b'
718
+ message: |-
719
+ RunSec Detection [AK-038]: CWE-203
720
+ languages:
721
+ - python
722
+ severity: WARNING
723
+ - id: runsec.auth-keycloak.ak-039
724
+ metadata:
725
+ runsec_version: v1.0
726
+ confidence: |-
727
+ 0.9
728
+ exploit_scenario: |-
729
+ N/A
730
+ fix_template: |-
731
+ Add proof-of-possession for renewal.
732
+ pattern-either:
733
+ - pattern: |-
734
+ refresh(rt)
735
+ - pattern-regex: 'Vulnerable:\\s*AK\\-039\\b'
736
+ message: |-
737
+ RunSec Detection [AK-039]: CWE-287
738
+ languages:
739
+ - python
740
+ severity: WARNING
741
+ - id: runsec.auth-keycloak.ak-040
742
+ metadata:
743
+ runsec_version: v1.0
744
+ confidence: |-
745
+ 0.9
746
+ exploit_scenario: |-
747
+ N/A
748
+ fix_template: |-
749
+ Re-authenticate before high-risk operations.
750
+ pattern-either:
751
+ - pattern: |-
752
+ perform_admin_action()
753
+ - pattern-regex: 'Vulnerable:\\s*AK\\-040\\b'
754
+ message: |-
755
+ RunSec Detection [AK-040]: CWE-306
756
+ languages:
757
+ - python
758
+ severity: WARNING
759
+ - id: runsec.auth-keycloak.ak-041
760
+ metadata:
761
+ runsec_version: v1.0
762
+ confidence: |-
763
+ 0.9
764
+ exploit_scenario: |-
765
+ N/A
766
+ fix_template: |-
767
+ Enforce temporal validation window.
768
+ pattern-either:
769
+ - pattern: |-
770
+ if validate_sig(token): accept()
771
+ - pattern-regex: 'Vulnerable:\\s*AK\\-041\\b'
772
+ message: |-
773
+ RunSec Detection [AK-041]: CWE-345
774
+ languages:
775
+ - python
776
+ severity: WARNING
777
+ - id: runsec.auth-keycloak.ak-042
778
+ metadata:
779
+ runsec_version: v1.0
780
+ confidence: |-
781
+ 0.9
782
+ exploit_scenario: |-
783
+ N/A
784
+ fix_template: |-
785
+ Rotate SID after external auth callback.
786
+ pattern-either:
787
+ - pattern: |-
788
+ handle_callback(); establish_session(old_sid)
789
+ - pattern-regex: 'Vulnerable:\\s*AK\\-042\\b'
790
+ message: |-
791
+ RunSec Detection [AK-042]: CWE-384
792
+ languages:
793
+ - python
794
+ severity: WARNING
795
+ - id: runsec.auth-keycloak.ak-043
796
+ metadata:
797
+ runsec_version: v1.0
798
+ confidence: |-
799
+ 0.9
800
+ exploit_scenario: |-
801
+ N/A
802
+ fix_template: |-
803
+ Revoke refresh family on risk events.
804
+ pattern-either:
805
+ - pattern: |-
806
+ ctx = fingerprint(request)
807
+ refresh(rt, ctx)
808
+ - pattern-regex: 'Vulnerable:\\s*AK\\-043\\b'
809
+ message: |-
810
+ RunSec Detection [AK-043]: CWE-613
811
+ languages:
812
+ - python
813
+ severity: WARNING
814
+ - id: runsec.auth-keycloak.ak-044
815
+ metadata:
816
+ runsec_version: v1.0
817
+ confidence: |-
818
+ 0.9
819
+ exploit_scenario: |-
820
+ N/A
821
+ fix_template: |-
822
+ Enforce replay-safe refresh identifiers.
823
+ pattern-either:
824
+ - pattern: |-
825
+ if validate_sig(rt): issue_new()
826
+ - pattern-regex: 'Vulnerable:\\s*AK\\-044\\b'
827
+ message: |-
828
+ RunSec Detection [AK-044]: CWE-345
829
+ languages:
830
+ - python
831
+ severity: WARNING