Skip to content

Commit 3e99bc6

Browse files
emmanuelgjrclaude
andcommitted
fix(scanner): confidence seeds for absence/presence rules, split JWT out of P02.9
- #19: move the JWT branch of P02.9 into a new P02.10 (warn / low) with the bundle/lockfile/snapshot exclude_globs; add a positive (jwt_config.py) and a negative (js-service/vendor.min.js) fixture. - #22: the CLI-executed P20.5 absence branch resolves to warn, P20.5 is low confidence; absence notes on P07.x, P08.x, P16.1, P17.1-P17.5 now say the absence WARN is low confidence (rule descriptions, notes, skill Step 2). - #23: P02.5 was already quote-optional (PR-11); add an unquoted positive and an env-sourced negative fixture and sync skill Step 2 with the YAML. - #24: all pass_signal rules are already medium; enforce it with a self-test. - regen_expected.py honours exclude_globs like the CLI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 36bee3c commit 3e99bc6

17 files changed

Lines changed: 235 additions & 98 deletions

‎dsgai_scanner_tool/CHANGES_v0.3.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ dates are ISO-8601. The previous line is recorded in [`CHANGES_v0.2.md`](CHANGES
88

99
## [Unreleased]
1010

11+
### Changed (rule confidence seeds + DSGAI02 precision — #19, #22, #23, #24)
12+
- **JWT literals split out of P02.9 into a new P02.10** (`raw-jwt-literal`, signal
13+
`warn`, confidence `low`), keeping the `*.min.js` / `dist/**` / `**/__snapshots__/**` /
14+
`*.lock` / `*.map` excludes. P02.9 keeps the provider-prefix tokens at `fail`/`high`.
15+
New fixtures: `jwt_config.py` (WARN) and `js-service/vendor.min.js` (must not fire). (#19)
16+
- **Absence-of-evidence verdicts are low-confidence WARNs.** The P20.5 absence branch
17+
(inference endpoint with neither P20.1 nor P20.2 within 15 lines) now resolves to
18+
`warn` instead of `fail`, and P20.5 is confidence `low`; the fixture JS `/chat`
19+
endpoint, and so DSGAI20 on the fixture, moves from FAIL to WARN. P07.1–P07.4,
20+
P08.1–P08.6, P16.1 and P17.1–P17.5 note the low-confidence absence WARN in their
21+
description/notes and in skill Step 2; their presence branches are unchanged. (#22)
22+
- **P02.5 quote-optional** (pattern already fixed in PR-11): added an unquoted
23+
`AZURE_OPENAI_KEY` positive in the fixture `.env` and an env-sourced negative in
24+
`good_config.py`; skill Step 2 now lists the quote-optional P02.1–P02.5 patterns and
25+
P02.9/P02.10, matching the YAML. (#23)
26+
- **Presence / PASS-signal rules stay at `medium` confidence** (seeded in PR-03), now
27+
enforced by a self-test so it cannot regress. (#24)
28+
- `tests/regen_expected.py` honours `exclude_globs`, as the CLI does.
29+
1130
### Fixed (hard-audit follow-up)
1231
- **CRITICAL — gitignored `.env` files are now scanned.** Discovery honored `.gitignore`,
1332
so the flagship "hardcoded key in `.env`" detection silently didn't run on real repos.

‎dsgai_scanner_tool/cli/dsgai_scan.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
"P06.5": {"violation": "fail", "satisfied": "info"},
5353
"P11.1": {"violation": "fail", "satisfied": "pass_signal"},
5454
"P18.4": {"violation": "warn", "satisfied": "pass_signal"},
55-
"P20.5": {"violation": "fail", "satisfied": "pass_signal"},
55+
# Absence of auth/rate limit near an endpoint is weak evidence (it is often
56+
# applied globally), so the violation is a low-confidence WARN (#22).
57+
"P20.5": {"violation": "warn", "satisfied": "pass_signal"},
5658
# Corroborating-signal rules: fire only when the nearby signal is PRESENT
5759
# (drop the match otherwise). P12.1 is a FAIL only when an LLM call is nearby.
5860
"P12.1": {"violation": "drop", "satisfied": "fail"},

‎dsgai_scanner_tool/dist/dsgai.semgrep.yaml‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ rules:
343343
- id: dsgai-P07.1
344344
languages: [generic]
345345
severity: INFO
346-
message: 'DSGAI07 P07.1: TTL config'
346+
message: 'DSGAI07 P07.1: TTL config (absence is a low-confidence WARN)'
347347
patterns:
348348
- pattern-regex: '(ttl\s*=|expires_in\s*=|max_age\s*=|RETENTION_DAYS|DATA_TTL|HISTORY_TTL)'
349349
paths:
@@ -356,7 +356,7 @@ rules:
356356
- id: dsgai-P07.2
357357
languages: [generic]
358358
severity: INFO
359-
message: 'DSGAI07 P07.2: Session cleanup (PASS)'
359+
message: 'DSGAI07 P07.2: Session cleanup (PASS; absence is a low-confidence WARN)'
360360
patterns:
361361
- pattern-regex: '(delete_session|clear_history|purge_conversation|clear_memory|delete_conversation)'
362362
paths:
@@ -369,7 +369,7 @@ rules:
369369
- id: dsgai-P07.3
370370
languages: [generic]
371371
severity: INFO
372-
message: 'DSGAI07 P07.3: Vector delete (PASS)'
372+
message: 'DSGAI07 P07.3: Vector delete (PASS; absence is a low-confidence WARN)'
373373
patterns:
374374
- pattern-regex: '(delete_namespace|delete_collection|drop_index|delete_index|reset_collection)'
375375
paths:
@@ -382,7 +382,7 @@ rules:
382382
- id: dsgai-P07.4
383383
languages: [generic]
384384
severity: INFO
385-
message: 'DSGAI07 P07.4: Right-to-erasure (PASS)'
385+
message: 'DSGAI07 P07.4: Right-to-erasure (PASS; absence is a low-confidence WARN)'
386386
patterns:
387387
- pattern-regex: '(gdpr_delete|erase_user_data|handle_deletion|right_to_erasure|forget_user)'
388388
paths:
@@ -395,7 +395,7 @@ rules:
395395
- id: dsgai-P08.1
396396
languages: [generic]
397397
severity: INFO
398-
message: 'DSGAI08 P08.1: DPIA / privacy assessment doc'
398+
message: 'DSGAI08 P08.1: DPIA / privacy assessment doc (absence is a low-confidence WARN)'
399399
patterns:
400400
- pattern-regex: '(DPIA|PIA|privacy_assessment|privacy[._-]impact)'
401401
paths:
@@ -408,7 +408,7 @@ rules:
408408
- id: dsgai-P08.2
409409
languages: [generic]
410410
severity: INFO
411-
message: 'DSGAI08 P08.2: Data processing agreement ref'
411+
message: 'DSGAI08 P08.2: Data processing agreement ref (absence is a low-confidence WARN)'
412412
patterns:
413413
- pattern-regex: '(data_processing_agreement|DPA|sub_processor)'
414414
paths:
@@ -421,7 +421,7 @@ rules:
421421
- id: dsgai-P08.3
422422
languages: [generic]
423423
severity: INFO
424-
message: 'DSGAI08 P08.3: Consent capture'
424+
message: 'DSGAI08 P08.3: Consent capture (absence is a low-confidence WARN)'
425425
patterns:
426426
- pattern-regex: '(consent_capture|capture_consent|consent_record|lawful_basis)'
427427
paths:
@@ -434,7 +434,7 @@ rules:
434434
- id: dsgai-P08.4
435435
languages: [generic]
436436
severity: INFO
437-
message: 'DSGAI08 P08.4: EU AI Act annotation'
437+
message: 'DSGAI08 P08.4: EU AI Act annotation (absence is a low-confidence WARN)'
438438
patterns:
439439
- pattern-regex: '(ai_act_risk_level|high_risk_ai|limited_risk|minimal_risk)'
440440
paths:
@@ -447,7 +447,7 @@ rules:
447447
- id: dsgai-P08.5
448448
languages: [generic]
449449
severity: INFO
450-
message: 'DSGAI08 P08.5: Audit logging'
450+
message: 'DSGAI08 P08.5: Audit logging (absence is a low-confidence WARN)'
451451
patterns:
452452
- pattern-regex: '(audit_log|decision_log|audit_trail)'
453453
paths:
@@ -460,7 +460,7 @@ rules:
460460
- id: dsgai-P08.6
461461
languages: [generic]
462462
severity: INFO
463-
message: 'DSGAI08 P08.6: Do-not-track honored'
463+
message: 'DSGAI08 P08.6: Do-not-track honored (absence is a low-confidence WARN)'
464464
patterns:
465465
- pattern-regex: '(do_not_track|opt_out|DNT)'
466466
paths:
@@ -785,7 +785,7 @@ rules:
785785
- id: dsgai-P17.1
786786
languages: [generic]
787787
severity: INFO
788-
message: 'DSGAI17 P17.1: Circuit breaker (PASS)'
788+
message: 'DSGAI17 P17.1: Circuit breaker (PASS; absence is a low-confidence WARN)'
789789
patterns:
790790
- pattern-regex: '(CircuitBreaker|@circuit|tenacity|resilience4j|pybreaker)'
791791
paths:
@@ -798,7 +798,7 @@ rules:
798798
- id: dsgai-P17.2
799799
languages: [generic]
800800
severity: INFO
801-
message: 'DSGAI17 P17.2: Retry with backoff (PASS)'
801+
message: 'DSGAI17 P17.2: Retry with backoff (PASS; absence is a low-confidence WARN)'
802802
patterns:
803803
- pattern-regex: '(retry\s*\(|@retry|exponential_backoff|max_retries\s*=|backoff_factor\s*=|retry_with_backoff)'
804804
paths:
@@ -811,7 +811,7 @@ rules:
811811
- id: dsgai-P17.3
812812
languages: [generic]
813813
severity: INFO
814-
message: 'DSGAI17 P17.3: Timeout on LLM call (PASS)'
814+
message: 'DSGAI17 P17.3: Timeout on LLM call (PASS; absence is a low-confidence WARN)'
815815
patterns:
816816
- pattern-regex: '(?m)(timeout\s*=\s*\d|request_timeout\s*=|httpx\.[^\n]{0,30}timeout)'
817817
paths:
@@ -824,7 +824,7 @@ rules:
824824
- id: dsgai-P17.4
825825
languages: [generic]
826826
severity: INFO
827-
message: 'DSGAI17 P17.4: Rate limit incoming (PASS)'
827+
message: 'DSGAI17 P17.4: Rate limit incoming (PASS; absence is a low-confidence WARN)'
828828
patterns:
829829
- pattern-regex: '(rate_limit|@throttle|RateLimiter|slowapi|flask_limiter|express-rate-limit)'
830830
paths:
@@ -837,7 +837,7 @@ rules:
837837
- id: dsgai-P17.5
838838
languages: [generic]
839839
severity: INFO
840-
message: 'DSGAI17 P17.5: Fallback response (PASS)'
840+
message: 'DSGAI17 P17.5: Fallback response (PASS; absence is a low-confidence WARN)'
841841
patterns:
842842
- pattern-regex: '(fallback_response|default_response|graceful_degradation|on_failure_return)'
843843
paths:
@@ -1032,15 +1032,15 @@ rules:
10321032
- id: dsgai-P20.5
10331033
languages: [generic]
10341034
severity: INFO
1035-
message: 'DSGAI20 P20.5: Inference endpoint (count)'
1035+
message: 'DSGAI20 P20.5: Inference endpoint (count; no auth/rate limit nearby is a low-confidence WARN)'
10361036
patterns:
10371037
- pattern-regex: '(?m)(@app\.(post|get)\(["''][^"'']*(chat|generate|completion|infer|predict)|@router\.(post|get)\(["''][^"'']*(chat|generate|completion|infer|predict)|app\.(post|get)\(["''][^"'']*(chat|generate|completion|infer|predict))'
10381038
paths:
10391039
include: ['*.py', '*.ts', '*.java', '*.kt', '*.go', '*.js']
10401040
metadata:
10411041
dsgai_control: DSGAI20
10421042
dsgai_rule: P20.5
1043-
confidence: medium
1043+
confidence: low
10441044
framework: 'dsgai-2026-v1.0'
10451045
- id: dsgai-P21.1
10461046
languages: [generic]

‎dsgai_scanner_tool/dsgai_scanner_prompt.md‎

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -681,17 +681,19 @@ Files: `*.py`, `*.ts`, `*.js`, `*.java`, `*.kt`, `*.go`, `*.env*`, `*.yaml`, `*.
681681

682682
Patterns (PCRE):
683683
```
684-
P02.1 Hardcoded LLM API key (OpenAI): (?i)(OPENAI_API_KEY|openai[._-]?api[._-]?key)\s*[:=]\s*["']sk-[A-Za-z0-9_\-]{20,}
685-
P02.2 Hardcoded LLM API key (Anthropic): (?i)(ANTHROPIC_API_KEY|anthropic[._-]?api[._-]?key)\s*[:=]\s*["']sk-ant-[A-Za-z0-9_\-]{20,}
686-
P02.3 Hardcoded Cohere/Google/HF tokens: (?i)(COHERE_API_KEY|GOOGLE_API_KEY|HF_TOKEN|HUGGINGFACE_TOKEN)\s*[:=]\s*["'][A-Za-z0-9_\-]{20,}
687-
P02.4 Hardcoded AWS creds: (AWS_ACCESS_KEY_ID|aws_access_key_id)\s*[:=]\s*["'][A-Z0-9]{16,}
688-
P02.5 Hardcoded Azure/GCP cred: (AZURE_OPENAI_KEY|GCP_SERVICE_ACCOUNT_KEY)\s*[:=]\s*["'][A-Za-z0-9_\-]{16,}
684+
P02.1 Hardcoded LLM API key (OpenAI): (?i)(OPENAI_API_KEY|openai[._-]?api[._-]?key)\s*[:=]\s*["']?sk-[A-Za-z0-9_\-]{20,}
685+
P02.2 Hardcoded LLM API key (Anthropic): (?i)(ANTHROPIC_API_KEY|anthropic[._-]?api[._-]?key)\s*[:=]\s*["']?sk-ant-[A-Za-z0-9_\-]{20,}
686+
P02.3 Hardcoded Cohere/Google/HF tokens: (?i)(COHERE_API_KEY|GOOGLE_API_KEY|HF_TOKEN|HUGGINGFACE_TOKEN)\s*[:=]\s*["']?[A-Za-z0-9_\-]{20,}
687+
P02.4 Hardcoded AWS creds: (AWS_ACCESS_KEY_ID|aws_access_key_id)\s*[:=]\s*["']?[A-Z0-9]{16,}
688+
P02.5 Hardcoded Azure/GCP cred: (AZURE_OPENAI_KEY|GCP_SERVICE_ACCOUNT_KEY)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}
689689
P02.6 Wildcard token scope (warn): ("scope"\s*:\s*"\*|permissions[^\n]{0,30}\*|scope[^\n]{0,20}admin)
690690
P02.7 Vault/secrets-manager (PASS): (hvac\.Client|hashicorp/vault|VAULT_(ADDR|TOKEN|NAMESPACE)|secretsmanager\.|GetSecretValue|SecretManagerServiceClient|azure[._-]keyvault|@aws-sdk/client-secrets-manager)
691691
P02.8 Tool-call signing (PASS): (hmac|sign_request|verify_signature|tool_auth|mtls|mutual_tls)
692+
P02.9 Raw token literal (any variable): \b(sk-ant-[A-Za-z0-9_\-]{20,}|sk-proj-[A-Za-z0-9_\-]{20,}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,}|xox[baprs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_\-]{35}|AKIA[0-9A-Z]{16})\b
693+
P02.10 Raw JWT literal (WARN, low): \beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b (skip *.min.js, dist/, __snapshots__/, *.lock, *.map)
692694
```
693695

694-
Treat P02.1–P02.5 hits as FAIL evidence. P02.6 as WARN. P02.7–P02.8 as PASS signals. Render per V5.
696+
Treat P02.1–P02.5 and P02.9 hits as FAIL evidence. P02.6 and P02.10 as WARN. P02.7–P02.8 as PASS signals. Render per V5.
695697

696698
### DSGAI03 Scan — Shadow AI Detection [STRUCTURAL]
697699

@@ -759,7 +761,7 @@ P07.3 Vector delete (PASS): (delete_namespace|delete_collection|drop_
759761
P07.4 Right-to-erasure (PASS): (gdpr_delete|erase_user_data|handle_deletion|right_to_erasure|forget_user)
760762
```
761763

762-
Absence of all four in a multi-tenant or PII-handling repo = WARN.
764+
Absence of all four in a multi-tenant or PII-handling repo = WARN (low confidence — absence of evidence, not evidence of absence).
763765

764766
### DSGAI08 Scan — Regulatory and Privacy Compliance [STRUCTURAL]
765767

@@ -774,7 +776,7 @@ P08.5 Audit logging: (audit_log|decision_log|audit_trail)
774776
P08.6 Do-not-track honored: (do_not_track|opt_out|DNT)
775777
```
776778

777-
Absence of all six in a production GenAI service = WARN; absence in a high-risk EU AI Act use case = FAIL.
779+
Absence of all six in a production GenAI service = WARN (low confidence); absence in a high-risk EU AI Act use case = FAIL.
778780

779781
### DSGAI09 Scan — Multimodal AI Data Security [STRUCTURAL]
780782

@@ -892,7 +894,7 @@ P16.3 Telemetry off (PASS): (telemetry[^\n]{0,10}(off|false|disabled)
892894
P16.4 Context scope limits: (contextWindow|ignorePaths|excludeFiles|maxContextLines)
893895
```
894896

895-
Absence of P16.1 in a repo with `.env` or `secrets/` directory = WARN.
897+
Absence of P16.1 in a repo with `.env` or `secrets/` directory = WARN (low confidence).
896898

897899
### DSGAI17 Scan — System Resilience and Availability [STRUCTURAL]
898900

@@ -907,7 +909,7 @@ P17.5 Fallback response (PASS): (fallback_response|default_response|grace
907909
P17.6 Unbounded retry (FAIL): while\s+True[^}]{0,200}(generate|complete|chat)|retry\s*\(\s*\)
908910
```
909911

910-
LLM-calling module with none of P17.1–P17.5 = WARN.
912+
LLM-calling module with none of P17.1–P17.5 = WARN (low confidence).
911913

912914
### DSGAI18 Scan — Model Output Security [STRUCTURAL]
913915

@@ -950,7 +952,7 @@ P20.4 Prompt injection detect (PASS): (prompt_injection_detect|detect_injection
950952
P20.5 Inference endpoint (count): (@app\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict)|@router\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict)|app\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict))
951953
```
952954

953-
For every P20.5 inference endpoint, verify P20.1 and P20.2 are nearby. Both absent = FAIL.
955+
For every P20.5 inference endpoint, verify P20.1 and P20.2 are nearby. Both absent = WARN (low confidence — auth and rate limiting are often applied globally, outside the window).
954956

955957
### DSGAI21 Scan — Knowledge Store Security [STRUCTURAL]
956958

‎dsgai_scanner_tool/dsgai_scanner_tool.md‎

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -680,17 +680,19 @@ Files: `*.py`, `*.ts`, `*.js`, `*.java`, `*.kt`, `*.go`, `*.env*`, `*.yaml`, `*.
680680

681681
Patterns (PCRE):
682682
```
683-
P02.1 Hardcoded LLM API key (OpenAI): (?i)(OPENAI_API_KEY|openai[._-]?api[._-]?key)\s*[:=]\s*["']sk-[A-Za-z0-9_\-]{20,}
684-
P02.2 Hardcoded LLM API key (Anthropic): (?i)(ANTHROPIC_API_KEY|anthropic[._-]?api[._-]?key)\s*[:=]\s*["']sk-ant-[A-Za-z0-9_\-]{20,}
685-
P02.3 Hardcoded Cohere/Google/HF tokens: (?i)(COHERE_API_KEY|GOOGLE_API_KEY|HF_TOKEN|HUGGINGFACE_TOKEN)\s*[:=]\s*["'][A-Za-z0-9_\-]{20,}
686-
P02.4 Hardcoded AWS creds: (AWS_ACCESS_KEY_ID|aws_access_key_id)\s*[:=]\s*["'][A-Z0-9]{16,}
687-
P02.5 Hardcoded Azure/GCP cred: (AZURE_OPENAI_KEY|GCP_SERVICE_ACCOUNT_KEY)\s*[:=]\s*["'][A-Za-z0-9_\-]{16,}
683+
P02.1 Hardcoded LLM API key (OpenAI): (?i)(OPENAI_API_KEY|openai[._-]?api[._-]?key)\s*[:=]\s*["']?sk-[A-Za-z0-9_\-]{20,}
684+
P02.2 Hardcoded LLM API key (Anthropic): (?i)(ANTHROPIC_API_KEY|anthropic[._-]?api[._-]?key)\s*[:=]\s*["']?sk-ant-[A-Za-z0-9_\-]{20,}
685+
P02.3 Hardcoded Cohere/Google/HF tokens: (?i)(COHERE_API_KEY|GOOGLE_API_KEY|HF_TOKEN|HUGGINGFACE_TOKEN)\s*[:=]\s*["']?[A-Za-z0-9_\-]{20,}
686+
P02.4 Hardcoded AWS creds: (AWS_ACCESS_KEY_ID|aws_access_key_id)\s*[:=]\s*["']?[A-Z0-9]{16,}
687+
P02.5 Hardcoded Azure/GCP cred: (AZURE_OPENAI_KEY|GCP_SERVICE_ACCOUNT_KEY)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}
688688
P02.6 Wildcard token scope (warn): ("scope"\s*:\s*"\*|permissions[^\n]{0,30}\*|scope[^\n]{0,20}admin)
689689
P02.7 Vault/secrets-manager (PASS): (hvac\.Client|hashicorp/vault|VAULT_(ADDR|TOKEN|NAMESPACE)|secretsmanager\.|GetSecretValue|SecretManagerServiceClient|azure[._-]keyvault|@aws-sdk/client-secrets-manager)
690690
P02.8 Tool-call signing (PASS): (hmac|sign_request|verify_signature|tool_auth|mtls|mutual_tls)
691+
P02.9 Raw token literal (any variable): \b(sk-ant-[A-Za-z0-9_\-]{20,}|sk-proj-[A-Za-z0-9_\-]{20,}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,}|xox[baprs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_\-]{35}|AKIA[0-9A-Z]{16})\b
692+
P02.10 Raw JWT literal (WARN, low): \beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b (skip *.min.js, dist/, __snapshots__/, *.lock, *.map)
691693
```
692694

693-
Treat P02.1–P02.5 hits as FAIL evidence. P02.6 as WARN. P02.7–P02.8 as PASS signals. Render per V5.
695+
Treat P02.1–P02.5 and P02.9 hits as FAIL evidence. P02.6 and P02.10 as WARN. P02.7–P02.8 as PASS signals. Render per V5.
694696

695697
### DSGAI03 Scan — Shadow AI Detection [STRUCTURAL]
696698

@@ -758,7 +760,7 @@ P07.3 Vector delete (PASS): (delete_namespace|delete_collection|drop_
758760
P07.4 Right-to-erasure (PASS): (gdpr_delete|erase_user_data|handle_deletion|right_to_erasure|forget_user)
759761
```
760762

761-
Absence of all four in a multi-tenant or PII-handling repo = WARN.
763+
Absence of all four in a multi-tenant or PII-handling repo = WARN (low confidence — absence of evidence, not evidence of absence).
762764

763765
### DSGAI08 Scan — Regulatory and Privacy Compliance [STRUCTURAL]
764766

@@ -773,7 +775,7 @@ P08.5 Audit logging: (audit_log|decision_log|audit_trail)
773775
P08.6 Do-not-track honored: (do_not_track|opt_out|DNT)
774776
```
775777

776-
Absence of all six in a production GenAI service = WARN; absence in a high-risk EU AI Act use case = FAIL.
778+
Absence of all six in a production GenAI service = WARN (low confidence); absence in a high-risk EU AI Act use case = FAIL.
777779

778780
### DSGAI09 Scan — Multimodal AI Data Security [STRUCTURAL]
779781

@@ -891,7 +893,7 @@ P16.3 Telemetry off (PASS): (telemetry[^\n]{0,10}(off|false|disabled)
891893
P16.4 Context scope limits: (contextWindow|ignorePaths|excludeFiles|maxContextLines)
892894
```
893895

894-
Absence of P16.1 in a repo with `.env` or `secrets/` directory = WARN.
896+
Absence of P16.1 in a repo with `.env` or `secrets/` directory = WARN (low confidence).
895897

896898
### DSGAI17 Scan — System Resilience and Availability [STRUCTURAL]
897899

@@ -906,7 +908,7 @@ P17.5 Fallback response (PASS): (fallback_response|default_response|grace
906908
P17.6 Unbounded retry (FAIL): while\s+True[^}]{0,200}(generate|complete|chat)|retry\s*\(\s*\)
907909
```
908910

909-
LLM-calling module with none of P17.1–P17.5 = WARN.
911+
LLM-calling module with none of P17.1–P17.5 = WARN (low confidence).
910912

911913
### DSGAI18 Scan — Model Output Security [STRUCTURAL]
912914

@@ -949,7 +951,7 @@ P20.4 Prompt injection detect (PASS): (prompt_injection_detect|detect_injection
949951
P20.5 Inference endpoint (count): (@app\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict)|@router\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict)|app\.(post|get)\(["'][^"']*(chat|generate|completion|infer|predict))
950952
```
951953

952-
For every P20.5 inference endpoint, verify P20.1 and P20.2 are nearby. Both absent = FAIL.
954+
For every P20.5 inference endpoint, verify P20.1 and P20.2 are nearby. Both absent = WARN (low confidence — auth and rate limiting are often applied globally, outside the window).
953955

954956
### DSGAI21 Scan — Knowledge Store Security [STRUCTURAL]
955957

0 commit comments

Comments
 (0)