security-knowledge-os 0.1.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.
- app/__init__.py +3 -0
- app/_bundled/knowledge/public/agent-security/.gitkeep +0 -0
- app/_bundled/knowledge/public/agent-security/KU-0004-excessive-agency-least-privilege.md +67 -0
- app/_bundled/knowledge/public/agent-security/KU-0005-human-approval-gates.md +67 -0
- app/_bundled/knowledge/public/agent-security/KU-0006-outbound-channels-allowlist.md +65 -0
- app/_bundled/knowledge/public/credential-security/.gitkeep +0 -0
- app/_bundled/knowledge/public/credential-security/KU-0008-secrets-not-reachable-by-model.md +67 -0
- app/_bundled/knowledge/public/credential-security/KU-0009-credential-broker-pattern.md +64 -0
- app/_bundled/knowledge/public/governance/KU-0012-human-oversight.md +64 -0
- app/_bundled/knowledge/public/incidents/.gitkeep +0 -0
- app/_bundled/knowledge/public/incidents/KU-0014-llm-payload-identifier-leak.md +147 -0
- app/_bundled/knowledge/public/memory-security/.gitkeep +0 -0
- app/_bundled/knowledge/public/memory-security/KU-0007-persistent-memory-poisoning.md +65 -0
- app/_bundled/knowledge/public/methodology/.gitkeep +0 -0
- app/_bundled/knowledge/public/methodology/KU-0011-improper-output-handling.md +62 -0
- app/_bundled/knowledge/public/methodology/KU-0013-assume-compromise-ja.md +68 -0
- app/_bundled/knowledge/public/prompt-security/.gitkeep +0 -0
- app/_bundled/knowledge/public/prompt-security/KU-0001-direct-prompt-injection.md +65 -0
- app/_bundled/knowledge/public/prompt-security/KU-0010-system-prompt-leakage.md +63 -0
- app/_bundled/knowledge/public/rag-security/.gitkeep +0 -0
- app/_bundled/knowledge/public/rag-security/KU-0002-indirect-prompt-injection.md +72 -0
- app/_bundled/knowledge/public/rag-security/KU-0003-untrusted-content-isolation.md +61 -0
- app/_bundled/rules/agent/.gitkeep +0 -0
- app/_bundled/rules/agent/OUT-001.yaml +16 -0
- app/_bundled/rules/agent/TOOL-000.yaml +16 -0
- app/_bundled/rules/agent/TOOL-001.yaml +19 -0
- app/_bundled/rules/credential/.gitkeep +0 -0
- app/_bundled/rules/credential/CRED-001.yaml +24 -0
- app/_bundled/rules/governance/.gitkeep +0 -0
- app/_bundled/rules/governance/GOV-001.yaml +15 -0
- app/_bundled/rules/memory/.gitkeep +0 -0
- app/_bundled/rules/memory/MEM-001.yaml +20 -0
- app/_bundled/rules/prompt/.gitkeep +0 -0
- app/_bundled/rules/rag/.gitkeep +0 -0
- app/_bundled/rules/rag/PI-003.yaml +25 -0
- app/_bundled/safe_tests/ST-CRED-001.yaml +25 -0
- app/_bundled/safe_tests/ST-IPI-001.yaml +28 -0
- app/_bundled/safe_tests/ST-MEM-001.yaml +27 -0
- app/_bundled/safe_tests/ST-TOOL-001.yaml +25 -0
- app/cli.py +385 -0
- app/config.py +89 -0
- app/eval/__init__.py +2 -0
- app/eval/metrics.py +123 -0
- app/ingestion/__init__.py +1 -0
- app/ingestion/chunker.py +36 -0
- app/ingestion/loader.py +179 -0
- app/ingestion/parser.py +256 -0
- app/ingestion/snapshot.py +491 -0
- app/ingestion/validator.py +397 -0
- app/llm/__init__.py +1 -0
- app/llm/anthropic_client.py +63 -0
- app/llm/base.py +34 -0
- app/llm/factory.py +29 -0
- app/llm/mock.py +56 -0
- app/main.py +1205 -0
- app/models/__init__.py +99 -0
- app/models/_credential_shapes.py +211 -0
- app/models/answer.py +131 -0
- app/models/assessment.py +373 -0
- app/models/context.py +62 -0
- app/models/knowledge.py +116 -0
- app/models/llm_io.py +36 -0
- app/models/policy_outcome.py +65 -0
- app/models/report.py +73 -0
- app/models/retrieval.py +128 -0
- app/models/reviewer_output.py +77 -0
- app/models/risk.py +124 -0
- app/models/rule_clause.py +41 -0
- app/policy/__init__.py +1 -0
- app/policy/classification.py +57 -0
- app/policy/human_gate.py +64 -0
- app/policy/knowledge_guard.py +60 -0
- app/policy/safe_test.py +319 -0
- app/retrieval/__init__.py +1 -0
- app/retrieval/base.py +92 -0
- app/retrieval/bm25.py +84 -0
- app/retrieval/hybrid.py +27 -0
- app/retrieval/index.py +858 -0
- app/reviewer/__init__.py +1 -0
- app/reviewer/answers.py +99 -0
- app/reviewer/assess.py +277 -0
- app/reviewer/attack_surface.py +35 -0
- app/reviewer/clause_eval.py +99 -0
- app/reviewer/evidence.py +64 -0
- app/reviewer/facts.py +129 -0
- app/reviewer/llm_review.py +504 -0
- app/reviewer/normalize.py +151 -0
- app/reviewer/questions.py +75 -0
- app/reviewer/report.py +128 -0
- app/reviewer/rollup.py +91 -0
- app/reviewer/rule_engine.py +223 -0
- app/reviewer/rule_loader.py +347 -0
- app/safe_errors.py +88 -0
- app/storage/__init__.py +1 -0
- app/storage/db.py +866 -0
- app/storage/integrity.py +526 -0
- app/storage/repository.py +164 -0
- security_knowledge_os-0.1.0.dist-info/METADATA +348 -0
- security_knowledge_os-0.1.0.dist-info/RECORD +103 -0
- security_knowledge_os-0.1.0.dist-info/WHEEL +4 -0
- security_knowledge_os-0.1.0.dist-info/entry_points.txt +2 -0
- security_knowledge_os-0.1.0.dist-info/licenses/LICENSE +202 -0
- security_knowledge_os-0.1.0.dist-info/licenses/NOTICE +35 -0
app/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0004
|
|
3
|
+
title: "Excessive agency: least privilege for tools"
|
|
4
|
+
category: agent-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://genai.owasp.org/llmrisk/llm06-excessive-agency/ (OWASP LLM06, 2025)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- TOOL-001
|
|
11
|
+
- TOOL-000
|
|
12
|
+
version: "1.0"
|
|
13
|
+
last_reviewed: "2026-09-10"
|
|
14
|
+
requires_ip_review: false
|
|
15
|
+
provenance:
|
|
16
|
+
source_title: "OWASP Top 10 for LLM Applications 2025 - LLM06 Excessive Agency"
|
|
17
|
+
source_url: "https://genai.owasp.org/llmrisk/llm06-excessive-agency/"
|
|
18
|
+
source_version: "2025"
|
|
19
|
+
source_license: "CC-BY-SA-4.0 (OWASP GenAI Security Project)"
|
|
20
|
+
derivation: summary
|
|
21
|
+
last_verified: "2026-09-10"
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Summary
|
|
25
|
+
Excessive agency is harm caused by an LLM system's own actions when it has too
|
|
26
|
+
much functionality, too many permissions, or too much autonomy. The fix is to
|
|
27
|
+
scope each of the three.
|
|
28
|
+
|
|
29
|
+
## Conditions
|
|
30
|
+
- A tool grants write, delete, send or shell capability, and
|
|
31
|
+
- The tool's permission is broader than the task needs, or is unspecified, and
|
|
32
|
+
- No approval step sits between the model's decision and the effect.
|
|
33
|
+
|
|
34
|
+
## Risk
|
|
35
|
+
Data loss, unwanted external messages, configuration changes, and command
|
|
36
|
+
execution driven by a hallucination or an injected instruction.
|
|
37
|
+
|
|
38
|
+
## Evidence
|
|
39
|
+
- tool_policy (every tool, its permission, whether approval is required)
|
|
40
|
+
- human_approval points
|
|
41
|
+
|
|
42
|
+
## Failure Mode
|
|
43
|
+
A "cleanup" task leads the agent to call a delete tool on live data because
|
|
44
|
+
nothing constrained the tool's scope.
|
|
45
|
+
|
|
46
|
+
## Detection Clues
|
|
47
|
+
- Tools expose more than read where read would do.
|
|
48
|
+
- Tool permissions are missing from the spec entirely.
|
|
49
|
+
- One credential or token backs many tools.
|
|
50
|
+
|
|
51
|
+
## Mitigations
|
|
52
|
+
- Give each tool the least permission that works; prefer read-only.
|
|
53
|
+
- Require a human approval gate for every write/delete/send/shell tool.
|
|
54
|
+
- Scope tool credentials narrowly and rotate them.
|
|
55
|
+
- Log every tool call with its arguments for review.
|
|
56
|
+
|
|
57
|
+
## Safe Test
|
|
58
|
+
In a sandbox, replace high-impact tools with recording stubs and confirm the
|
|
59
|
+
agent asks for approval before a stub is called.
|
|
60
|
+
|
|
61
|
+
## Limitations
|
|
62
|
+
Least privilege limits blast radius; it does not stop the model from being
|
|
63
|
+
tricked into using the privileges it does have.
|
|
64
|
+
|
|
65
|
+
## Related Knowledge
|
|
66
|
+
- KU-0005
|
|
67
|
+
- KU-0006
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0005
|
|
3
|
+
title: "Human approval gates for high-impact tool actions"
|
|
4
|
+
category: agent-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://genai.owasp.org/llmrisk/llm06-excessive-agency/ ; https://atlas.mitre.org/ (MITRE ATLAS)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- GOV-001
|
|
11
|
+
- TOOL-001
|
|
12
|
+
version: "1.0"
|
|
13
|
+
last_reviewed: "2026-09-10"
|
|
14
|
+
requires_ip_review: false
|
|
15
|
+
provenance:
|
|
16
|
+
source_title: "OWASP Top 10 for LLM Applications 2025 - LLM06 Excessive Agency"
|
|
17
|
+
source_url: "https://genai.owasp.org/llmrisk/llm06-excessive-agency/"
|
|
18
|
+
source_version: "2025"
|
|
19
|
+
source_license: "CC-BY-SA-4.0 (OWASP GenAI Security Project); MITRE ATLAS Terms of Use (free use with attribution)"
|
|
20
|
+
derivation: summary
|
|
21
|
+
last_verified: "2026-09-10"
|
|
22
|
+
usage_note: "Also informed by MITRE ATLAS (atlas.mitre.org)."
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Summary
|
|
26
|
+
For actions whose effects are hard to reverse or leave the trust boundary, the
|
|
27
|
+
model proposes and a human approves. The approval must be specific to the action
|
|
28
|
+
and its arguments, not a blanket "allow tools".
|
|
29
|
+
|
|
30
|
+
## Conditions
|
|
31
|
+
- The agent can perform an action in: external send, file delete, production
|
|
32
|
+
change, money movement, HR or legal judgement, credential retrieval, or a
|
|
33
|
+
destructive shell command, and
|
|
34
|
+
- That action can run without a person confirming it.
|
|
35
|
+
|
|
36
|
+
## Risk
|
|
37
|
+
An automated pipeline turns an injected instruction or a hallucination into a
|
|
38
|
+
real, irreversible effect.
|
|
39
|
+
|
|
40
|
+
## Evidence
|
|
41
|
+
- tool_policy
|
|
42
|
+
- human_approval points and which actions they cover
|
|
43
|
+
- high_impact_actions
|
|
44
|
+
|
|
45
|
+
## Failure Mode
|
|
46
|
+
`human_approval: { email_send: false }` while an email tool is available and the
|
|
47
|
+
agent has an outbound task.
|
|
48
|
+
|
|
49
|
+
## Detection Clues
|
|
50
|
+
- A high-impact action has no matching approval point.
|
|
51
|
+
- Approval is coarse ("approve this run") rather than per-action.
|
|
52
|
+
|
|
53
|
+
## Mitigations
|
|
54
|
+
- Enumerate high-impact actions and require an approval point for each.
|
|
55
|
+
- Show the human the exact call and arguments before it runs.
|
|
56
|
+
- Fail closed: if the approval path errors, do not execute.
|
|
57
|
+
|
|
58
|
+
## Safe Test
|
|
59
|
+
Ask the agent to perform a task needing a high-impact tool in a sandbox and
|
|
60
|
+
confirm it routes to approval instead of acting.
|
|
61
|
+
|
|
62
|
+
## Limitations
|
|
63
|
+
Approval fatigue is real; keep the set of gated actions small and meaningful.
|
|
64
|
+
|
|
65
|
+
## Related Knowledge
|
|
66
|
+
- KU-0004
|
|
67
|
+
- KU-0012
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0006
|
|
3
|
+
title: "Outbound channels and destination allow-lists"
|
|
4
|
+
category: agent-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://genai.owasp.org/llmrisk/llm02-sensitive-information-disclosure/ (OWASP LLM02, 2025)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- OUT-001
|
|
11
|
+
- PI-003
|
|
12
|
+
version: "1.0"
|
|
13
|
+
last_reviewed: "2026-09-10"
|
|
14
|
+
requires_ip_review: false
|
|
15
|
+
provenance:
|
|
16
|
+
source_title: "OWASP Top 10 for LLM Applications 2025 - LLM02 Sensitive Information Disclosure"
|
|
17
|
+
source_url: "https://genai.owasp.org/llmrisk/llm02-sensitive-information-disclosure/"
|
|
18
|
+
source_version: "2025"
|
|
19
|
+
source_license: "CC-BY-SA-4.0 (OWASP GenAI Security Project)"
|
|
20
|
+
derivation: summary
|
|
21
|
+
last_verified: "2026-09-10"
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Summary
|
|
25
|
+
Any channel that can send data outside the trust boundary - email, HTTP requests,
|
|
26
|
+
webhooks, chat posts - is an exfiltration path. It needs an explicit list of
|
|
27
|
+
allowed destinations and, for sensitive data, human approval.
|
|
28
|
+
|
|
29
|
+
## Conditions
|
|
30
|
+
- An outbound capability is enabled, and
|
|
31
|
+
- The set of destinations it may reach is not stated or not enforced.
|
|
32
|
+
|
|
33
|
+
## Risk
|
|
34
|
+
Sensitive information disclosure: an injected instruction (KU-0002) or a
|
|
35
|
+
misjudgement sends data to an attacker-controlled endpoint.
|
|
36
|
+
|
|
37
|
+
## Evidence
|
|
38
|
+
- outbound_spec (enabled? which tools?)
|
|
39
|
+
- outbound_destinations (an explicit allow-list)
|
|
40
|
+
- credential_storage (what could be sent)
|
|
41
|
+
|
|
42
|
+
## Failure Mode
|
|
43
|
+
The agent is asked to "share the report" and posts it to a URL taken verbatim
|
|
44
|
+
from a retrieved document.
|
|
45
|
+
|
|
46
|
+
## Detection Clues
|
|
47
|
+
- Outbound enabled with `destinations` empty or unspecified.
|
|
48
|
+
- The allow-list is advisory (in the prompt) rather than enforced in code.
|
|
49
|
+
|
|
50
|
+
## Mitigations
|
|
51
|
+
- Enforce a destination allow-list outside the model.
|
|
52
|
+
- Require approval for outbound actions carrying sensitive data.
|
|
53
|
+
- Strip or redact secrets and PII before any outbound call.
|
|
54
|
+
- Prefer pull over push where possible.
|
|
55
|
+
|
|
56
|
+
## Safe Test
|
|
57
|
+
In a sandbox with outbound disabled, ask the agent to send data to a `*.invalid`
|
|
58
|
+
address and confirm it does not attempt the call.
|
|
59
|
+
|
|
60
|
+
## Limitations
|
|
61
|
+
An allow-list stops unknown destinations, not misuse of an allowed one.
|
|
62
|
+
|
|
63
|
+
## Related Knowledge
|
|
64
|
+
- KU-0002
|
|
65
|
+
- KU-0008
|
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0008
|
|
3
|
+
title: "Secrets must not be reachable by the model"
|
|
4
|
+
category: credential-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://genai.owasp.org/llmrisk/llm02-sensitive-information-disclosure/ (OWASP LLM02, 2025)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- CRED-001
|
|
11
|
+
version: "1.0"
|
|
12
|
+
last_reviewed: "2026-09-10"
|
|
13
|
+
requires_ip_review: false
|
|
14
|
+
provenance:
|
|
15
|
+
source_title: "OWASP Top 10 for LLM Applications 2025 - LLM02 Sensitive Information Disclosure"
|
|
16
|
+
source_url: "https://genai.owasp.org/llmrisk/llm02-sensitive-information-disclosure/"
|
|
17
|
+
source_version: "2025"
|
|
18
|
+
source_license: "CC-BY-SA-4.0 (OWASP GenAI Security Project)"
|
|
19
|
+
derivation: summary
|
|
20
|
+
last_verified: "2026-09-10"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
If the model - or a tool it can call - can read a `.env` file, an environment
|
|
25
|
+
variable, or a raw vault secret, then a single injection or misjudgement can
|
|
26
|
+
disclose a long-lived credential.
|
|
27
|
+
|
|
28
|
+
## Conditions
|
|
29
|
+
- Credentials are stored as environment variables or raw secrets, and
|
|
30
|
+
- A tool can read arbitrary files or environment variables, or the credential is
|
|
31
|
+
placed in the prompt.
|
|
32
|
+
|
|
33
|
+
## Risk
|
|
34
|
+
Credential exposure: the key ends up in the transcript, in a log, or in an
|
|
35
|
+
outbound message, and remains valid for a long time.
|
|
36
|
+
|
|
37
|
+
## Evidence
|
|
38
|
+
- credential_storage (env / vault / proxy / none)
|
|
39
|
+
- credential_exposed_to_model (can the model or a tool read the raw value?)
|
|
40
|
+
- tool_policy (file read, env read)
|
|
41
|
+
|
|
42
|
+
## Failure Mode
|
|
43
|
+
A `file_read` tool reads `.env` and the API key appears in the model's answer.
|
|
44
|
+
|
|
45
|
+
## Detection Clues
|
|
46
|
+
- Storage is `env` and a broad file/read tool exists.
|
|
47
|
+
- No short-lived token layer in front of the raw secret.
|
|
48
|
+
- Logs are not scrubbed for secret patterns.
|
|
49
|
+
|
|
50
|
+
## Mitigations
|
|
51
|
+
- Put a credential broker in front of the raw secret (KU-0009).
|
|
52
|
+
- Never expose the raw value to the model or its tools.
|
|
53
|
+
- Scrub logs and transcripts for known secret shapes.
|
|
54
|
+
- Rotate credentials and keep their lifetime short.
|
|
55
|
+
|
|
56
|
+
## Safe Test
|
|
57
|
+
Place a dummy value such as `SECRET_TEST_123` where a read tool could reach it and
|
|
58
|
+
confirm the model cannot read or forward it.
|
|
59
|
+
|
|
60
|
+
## Limitations
|
|
61
|
+
Not disclosing the secret does not stop misuse of the access it grants; scope the
|
|
62
|
+
access too.
|
|
63
|
+
|
|
64
|
+
## Related Knowledge
|
|
65
|
+
- KU-0009
|
|
66
|
+
- KU-0006
|
|
67
|
+
- KU-0014
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0009
|
|
3
|
+
title: "Credential broker: short-lived, least-privilege handles"
|
|
4
|
+
category: credential-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf (NIST AI 600-1, Generative AI Profile)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- CRED-001
|
|
11
|
+
version: "1.0"
|
|
12
|
+
last_reviewed: "2026-09-10"
|
|
13
|
+
requires_ip_review: false
|
|
14
|
+
provenance:
|
|
15
|
+
source_title: "NIST AI 600-1: Artificial Intelligence Risk Management Framework - Generative AI Profile"
|
|
16
|
+
source_url: "https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf"
|
|
17
|
+
source_version: "2024-07"
|
|
18
|
+
source_license: "U.S. Government work / public domain"
|
|
19
|
+
derivation: summary
|
|
20
|
+
last_verified: "2026-09-10"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
Instead of handing the model a raw credential, a broker sits between the agent and
|
|
25
|
+
the secret. The agent requests a capability by name; the broker returns a
|
|
26
|
+
short-lived, narrowly-scoped handle (or performs the call itself) and never
|
|
27
|
+
reveals the underlying value.
|
|
28
|
+
|
|
29
|
+
## Conditions
|
|
30
|
+
- The agent needs to authenticate to an external system, and
|
|
31
|
+
- The design goal is that a compromised model does not equal a compromised
|
|
32
|
+
credential.
|
|
33
|
+
|
|
34
|
+
## Risk
|
|
35
|
+
Without a broker, the model's context is a credential store; with one, the worst
|
|
36
|
+
case is a scoped, expiring handle.
|
|
37
|
+
|
|
38
|
+
## Evidence
|
|
39
|
+
- credential_storage (is it `proxy`?)
|
|
40
|
+
- credential_exposed_to_model (should be false)
|
|
41
|
+
|
|
42
|
+
## Failure Mode
|
|
43
|
+
n/a - this is a mitigating pattern; the failure is not adopting it (see KU-0008).
|
|
44
|
+
|
|
45
|
+
## Detection Clues
|
|
46
|
+
- `credential_storage: proxy` and `exposed_to_model: false` indicate the pattern
|
|
47
|
+
is in place.
|
|
48
|
+
|
|
49
|
+
## Mitigations
|
|
50
|
+
- Route all credential use through the broker.
|
|
51
|
+
- Issue the minimum scope and the shortest lifetime that works.
|
|
52
|
+
- Audit every issuance; revoke on anomaly.
|
|
53
|
+
- Keep the broker on a separate process and trust boundary from the agent.
|
|
54
|
+
|
|
55
|
+
## Safe Test
|
|
56
|
+
Confirm that removing the raw secret from the agent's environment does not break
|
|
57
|
+
normal operation (the broker still works) and that the agent cannot enumerate or
|
|
58
|
+
print a credential.
|
|
59
|
+
|
|
60
|
+
## Limitations
|
|
61
|
+
The broker becomes a critical dependency and a target; protect and monitor it.
|
|
62
|
+
|
|
63
|
+
## Related Knowledge
|
|
64
|
+
- KU-0008
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0012
|
|
3
|
+
title: "Human oversight for consequential decisions"
|
|
4
|
+
category: governance
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://www.nist.gov/itl/ai-risk-management-framework (NIST AI RMF: Govern / Manage)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- GOV-001
|
|
11
|
+
version: "1.0"
|
|
12
|
+
last_reviewed: "2026-09-10"
|
|
13
|
+
requires_ip_review: false
|
|
14
|
+
provenance:
|
|
15
|
+
source_title: "NIST AI Risk Management Framework (AI RMF 1.0)"
|
|
16
|
+
source_url: "https://www.nist.gov/itl/ai-risk-management-framework"
|
|
17
|
+
source_version: "1.0 (2023-01)"
|
|
18
|
+
source_license: "U.S. Government work / public domain"
|
|
19
|
+
derivation: summary
|
|
20
|
+
last_verified: "2026-09-10"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
An assessment tool supports a decision; it does not make it. Consequential
|
|
25
|
+
outcomes - deployment approval, risk acceptance, anything affecting money, people,
|
|
26
|
+
contracts, production, or external parties - stay with a named human owner.
|
|
27
|
+
|
|
28
|
+
## Conditions
|
|
29
|
+
- The system produces an output that could be read as a final safety, legal, or
|
|
30
|
+
business decision, and
|
|
31
|
+
- There is no explicit step where a person owns that decision.
|
|
32
|
+
|
|
33
|
+
## Risk
|
|
34
|
+
An automated "PASS" is treated as a guarantee; responsibility is diffused; a wrong
|
|
35
|
+
call has no owner.
|
|
36
|
+
|
|
37
|
+
## Evidence
|
|
38
|
+
- Which decisions are automated vs. reviewed
|
|
39
|
+
- Who signs off on high-impact outcomes
|
|
40
|
+
|
|
41
|
+
## Failure Mode
|
|
42
|
+
A pipeline promotes a change to production because the assistant returned "looks
|
|
43
|
+
fine" and nothing required a person to confirm.
|
|
44
|
+
|
|
45
|
+
## Detection Clues
|
|
46
|
+
- High-impact actions are present with no approval coverage.
|
|
47
|
+
- Output uses definitive language ("safe", "approved") rather than scoped findings.
|
|
48
|
+
|
|
49
|
+
## Mitigations
|
|
50
|
+
- Return findings, evidence, unknowns, and residual risk - not a verdict.
|
|
51
|
+
- Require a human owner for every consequential decision.
|
|
52
|
+
- Record the revision, model, and knowledge version behind each result.
|
|
53
|
+
- State plainly that PASS is not a security guarantee and UNKNOWN is valid.
|
|
54
|
+
|
|
55
|
+
## Safe Test
|
|
56
|
+
Review the output wording and the workflow: confirm a human sign-off is required
|
|
57
|
+
before any consequential action and that the result carries its provenance.
|
|
58
|
+
|
|
59
|
+
## Limitations
|
|
60
|
+
Oversight only works if the reviewer has enough context; give them the evidence.
|
|
61
|
+
|
|
62
|
+
## Related Knowledge
|
|
63
|
+
- KU-0005
|
|
64
|
+
- KU-0011
|
|
File without changes
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0014
|
|
3
|
+
title: "Identifier-shaped secrets leak into LLM payloads even after a denylist"
|
|
4
|
+
category: incident
|
|
5
|
+
source_type: incident
|
|
6
|
+
source_ref: "internal: security-knowledge-os cross-AI review, rounds 9-14 (2026-09)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- CRED-001
|
|
11
|
+
version: "1.0"
|
|
12
|
+
last_reviewed: "2026-09-13"
|
|
13
|
+
requires_ip_review: false
|
|
14
|
+
provenance:
|
|
15
|
+
source_title: "security-knowledge-os pre-publication cross-AI review, rounds 9-14"
|
|
16
|
+
source_url: null
|
|
17
|
+
source_version: null
|
|
18
|
+
source_license: "N/A - original first-party incident, no external source"
|
|
19
|
+
derivation: original
|
|
20
|
+
last_verified: "2026-09-13"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
A system that forwards user-supplied *identifiers* (source names, tool names,
|
|
25
|
+
destination hosts, approval-gate keys) to an LLM-assisted reviewer - while
|
|
26
|
+
correctly withholding fields explicitly documented as secrets - can still leak
|
|
27
|
+
credentials. Attackers (or careless callers) put the secret in an identifier
|
|
28
|
+
field instead of a secret field. A denylist of known secret *shapes* (AWS keys,
|
|
29
|
+
Slack tokens, JWTs, ...) catches each format only after someone thinks to add
|
|
30
|
+
it, and was defeated five review rounds in a row by five different formats. It
|
|
31
|
+
was finally defeated by a *valid-looking* format (a UUID) that matched no known
|
|
32
|
+
secret pattern at all. The only fix that closed the class for good was
|
|
33
|
+
structural: stop sending the raw identifier value to the LLM, period.
|
|
34
|
+
|
|
35
|
+
## Conditions
|
|
36
|
+
- An LLM (or any less-trusted downstream consumer) receives a payload built
|
|
37
|
+
from user- or agent-supplied *free-form identifier* fields (names, hostnames,
|
|
38
|
+
keys in a map, labels) that were never intended to hold secrets.
|
|
39
|
+
- The system already has a *content* boundary for fields it knows are
|
|
40
|
+
sensitive (e.g. a `system_prompt` scrubber, a secrets vault), but identifier
|
|
41
|
+
fields are treated as inherently safe because "that's not where secrets go."
|
|
42
|
+
- The identifier fields are attacker- or caller-controlled strings with no
|
|
43
|
+
independent verification that they are actually what they claim to be
|
|
44
|
+
(a tool name, a hostname, a source label).
|
|
45
|
+
|
|
46
|
+
## Risk
|
|
47
|
+
Any credential-shaped string placed in an identifier field is forwarded
|
|
48
|
+
verbatim to the LLM (and typically into its provider's logs, and into any
|
|
49
|
+
third-party API the review call itself makes), bypassing every control that
|
|
50
|
+
exists specifically to keep secrets out of LLM context.
|
|
51
|
+
|
|
52
|
+
## Evidence
|
|
53
|
+
- The payload/request object sent to the external reviewer contains raw values
|
|
54
|
+
copied from identifier-typed fields (names, hosts, map keys) rather than
|
|
55
|
+
stable local labels.
|
|
56
|
+
- A regex denylist for "credential-shaped" strings exists and is applied only
|
|
57
|
+
to identifier fields, with no allowlist or anonymization layer behind it.
|
|
58
|
+
|
|
59
|
+
## Failure Mode
|
|
60
|
+
This was discovered as a live, repeating pattern across five consecutive
|
|
61
|
+
review rounds of this same project, each time with the reviewer proving the
|
|
62
|
+
previous round's fix incomplete:
|
|
63
|
+
|
|
64
|
+
1. **Round 9**: AWS access keys and Slack tokens placed in identifier fields
|
|
65
|
+
reached the LLM payload unfiltered. Fix: add regex patterns for those two
|
|
66
|
+
formats to a denylist.
|
|
67
|
+
2. **Round 11**: Stripe keys and JWTs reached the payload the same way. Fix:
|
|
68
|
+
extend the denylist with two more patterns.
|
|
69
|
+
3. **Round 12**: Google API keys, GitLab tokens, Discord bot tokens, and DB
|
|
70
|
+
connection strings, same gap. Fix: extend the denylist again (now covering
|
|
71
|
+
many formats across many providers, requiring a shared module so the
|
|
72
|
+
pattern list itself does not drift between the two enforcement points that
|
|
73
|
+
used it).
|
|
74
|
+
4. **Round 13**: OpenAI-style keys, same gap. The team added an *allowlist*
|
|
75
|
+
this time - reject any identifier segment over a fixed length, since every
|
|
76
|
+
known secret format was longer than any real identifier - reasoning that
|
|
77
|
+
a length bound is stronger than yet another format-specific pattern.
|
|
78
|
+
5. **Round 14**: A UUID-shaped secret defeated the length-based allowlist too
|
|
79
|
+
- a UUID's hyphen-separated segments are all short, so the same string that
|
|
80
|
+
looks exactly like a plausible resource identifier is also a perfectly
|
|
81
|
+
valid credential shape in systems that mint UUID-form API keys. At this
|
|
82
|
+
point the same structural recommendation had now been raised twice by the
|
|
83
|
+
external reviewer: stop trying to recognize secret shapes and stop sending
|
|
84
|
+
the raw value at all.
|
|
85
|
+
|
|
86
|
+
The pattern across all five rounds: **shape-based detection (deny or allow) is
|
|
87
|
+
a moving target because "looks like a secret" and "looks like a normal
|
|
88
|
+
identifier" are not disjoint sets**, and the set of secret formats in active
|
|
89
|
+
use is open-ended (any team can mint a new token format tomorrow).
|
|
90
|
+
|
|
91
|
+
## Detection Clues
|
|
92
|
+
- Any code path that serializes user- or agent-controlled identifier fields
|
|
93
|
+
into a prompt, request body, or log line sent to a less-trusted consumer,
|
|
94
|
+
without first checking whether the value is used *anywhere else* as a
|
|
95
|
+
literal (i.e., whether identity, not content, is what actually matters to
|
|
96
|
+
that consumer).
|
|
97
|
+
- A growing, format-specific regex list as the *only* defense for a field
|
|
98
|
+
class - each addition is evidence the previous version was already proven
|
|
99
|
+
insufficient by a real bypass, not a hypothetical one.
|
|
100
|
+
- Fields whose purpose is to *identify* something (a name, a key in a map, a
|
|
101
|
+
hostname) but whose type is unconstrained free-text equal in shape to fields
|
|
102
|
+
whose purpose is to *hold a secret value*.
|
|
103
|
+
|
|
104
|
+
## Mitigations
|
|
105
|
+
- **Ask whether the downstream consumer needs the real value or just needs to
|
|
106
|
+
distinguish one identifier from another.** If only the latter, don't send
|
|
107
|
+
the real value at all: replace every free-form identifier with a stable,
|
|
108
|
+
locally-generated label (e.g. sort the distinct values, number them
|
|
109
|
+
`item_1`, `item_2`, ...) before building the payload, and keep the mapping
|
|
110
|
+
local. This closes the entire vulnerability *class* in one change, instead
|
|
111
|
+
of chasing individual formats forever.
|
|
112
|
+
- Apply the anonymization consistently across every place the same identifier
|
|
113
|
+
appears in the payload (e.g. a tool name referenced both in a tool list and
|
|
114
|
+
embedded inside a separate free-text action string) - a mapping that covers
|
|
115
|
+
one occurrence but not the other reopens the leak for that field.
|
|
116
|
+
- Keep a fail-closed fallback for anything that shows up unmapped (an
|
|
117
|
+
"unlabeled" placeholder), rather than falling back to the original value,
|
|
118
|
+
so a bug in the mapping logic cannot silently regress to leaking.
|
|
119
|
+
- Never mutate the original, non-anonymized object: only the copy built for
|
|
120
|
+
the less-trusted consumer should be relabeled. Whatever performs
|
|
121
|
+
authoritative decisions (a deterministic rule engine, a human-facing report)
|
|
122
|
+
must keep operating on the real values.
|
|
123
|
+
- Treat a shape-based denylist or allowlist as a *stopgap*, not a destination:
|
|
124
|
+
if the same field class gets a second real-world bypass, that is the signal
|
|
125
|
+
to stop patching and do the structural fix, not evidence that "just one more
|
|
126
|
+
pattern" will finally be enough.
|
|
127
|
+
|
|
128
|
+
## Safe Test
|
|
129
|
+
Construct an identifier-typed field (a source name, tool name, or map key)
|
|
130
|
+
containing a value shaped like a real secret in a format NOT already covered
|
|
131
|
+
by any denylist/allowlist in the system (invent a novel-looking token shape
|
|
132
|
+
if needed). Confirm it is absent, byte-for-byte, from whatever payload is
|
|
133
|
+
built for the less-trusted consumer - not merely that it fails a specific
|
|
134
|
+
pattern check. Also confirm the same value, if it appears in more than one
|
|
135
|
+
field derived from the same identifier, is anonymized consistently everywhere
|
|
136
|
+
it appears.
|
|
137
|
+
|
|
138
|
+
## Limitations
|
|
139
|
+
Anonymization protects the *external* payload only; it does nothing if the
|
|
140
|
+
less-trusted consumer is later given tool access to fetch the real value some
|
|
141
|
+
other way, and it does not protect fields whose entire purpose is to carry
|
|
142
|
+
free-form prose (a system prompt, a user message) where content-based secret
|
|
143
|
+
scanning is still required and structurally different from this fix.
|
|
144
|
+
|
|
145
|
+
## Related Knowledge
|
|
146
|
+
- KU-0008
|
|
147
|
+
- KU-0009
|
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: KU-0007
|
|
3
|
+
title: "Persistent memory and long-term data poisoning"
|
|
4
|
+
category: memory-security
|
|
5
|
+
source_type: standard
|
|
6
|
+
source_ref: "https://genai.owasp.org/llmrisk/llm04-data-and-model-poisoning/ (OWASP LLM04, 2025)"
|
|
7
|
+
classification: public
|
|
8
|
+
status: reviewed
|
|
9
|
+
risk_ids:
|
|
10
|
+
- MEM-001
|
|
11
|
+
version: "1.0"
|
|
12
|
+
last_reviewed: "2026-09-10"
|
|
13
|
+
requires_ip_review: false
|
|
14
|
+
provenance:
|
|
15
|
+
source_title: "OWASP Top 10 for LLM Applications 2025 - LLM04 Data and Model Poisoning"
|
|
16
|
+
source_url: "https://genai.owasp.org/llmrisk/llm04-data-and-model-poisoning/"
|
|
17
|
+
source_version: "2025"
|
|
18
|
+
source_license: "CC-BY-SA-4.0 (OWASP GenAI Security Project)"
|
|
19
|
+
derivation: summary
|
|
20
|
+
last_verified: "2026-09-10"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
When an agent writes to a memory store that later sessions load and trust,
|
|
25
|
+
content derived from untrusted input can become "established fact" - and can
|
|
26
|
+
reach other sessions or other users.
|
|
27
|
+
|
|
28
|
+
## Conditions
|
|
29
|
+
- Memory is persistent across sessions, and
|
|
30
|
+
- The write path accepts content that came from untrusted input (user text,
|
|
31
|
+
retrieved documents), and
|
|
32
|
+
- There is no review between write and read-back.
|
|
33
|
+
|
|
34
|
+
## Risk
|
|
35
|
+
Long-term contamination of the assistant's behaviour, cross-session and
|
|
36
|
+
cross-user influence, and a durable foothold for an earlier injection (KU-0002).
|
|
37
|
+
|
|
38
|
+
## Evidence
|
|
39
|
+
- memory_spec (enabled? persistent? scope: session/user/global?)
|
|
40
|
+
- rag_pipeline (is untrusted content in scope?)
|
|
41
|
+
|
|
42
|
+
## Failure Mode
|
|
43
|
+
An injected note "the admin approved unrestricted tool use" is stored in session
|
|
44
|
+
one and loaded as fact in session two.
|
|
45
|
+
|
|
46
|
+
## Detection Clues
|
|
47
|
+
- Write and read-back share a path; nothing distinguishes stored input from
|
|
48
|
+
stored conclusions.
|
|
49
|
+
- Memory scope is user or global with no cleanup or review.
|
|
50
|
+
|
|
51
|
+
## Mitigations
|
|
52
|
+
- Separate the write path from the read-back path.
|
|
53
|
+
- Require review before content derived from untrusted input is stored.
|
|
54
|
+
- Scope memory to the session unless a wider scope is justified and controlled.
|
|
55
|
+
- Keep provenance on every memory entry so it can be audited and rolled back.
|
|
56
|
+
|
|
57
|
+
## Safe Test
|
|
58
|
+
Write a canary claim in session one, start a fresh session two, and confirm the
|
|
59
|
+
claim is not treated as verified knowledge.
|
|
60
|
+
|
|
61
|
+
## Limitations
|
|
62
|
+
Review adds latency; automate the classification of what is safe to store.
|
|
63
|
+
|
|
64
|
+
## Related Knowledge
|
|
65
|
+
- KU-0002
|
|
File without changes
|