You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**MCP inputSchema hardening** (`cmd/odek/mcp_approval.go`) — every string in an MCP tool's `inputSchema` is recursively guard-scanned for injection patterns; schemas larger than 256 KiB are rejected; the interactive approval prompt shows a SHA-256 hash and byte size of the schema so operators can detect changes.
179
179
-**MCP tool batch classification** (`internal/loop/loop.go`) — MCP tools (`<server>__<tool>`) are classified as `unknown` by `classifyToolCall`, so the batch approval gate shows them and untrusted sub-agents force them to `deny`.
180
180
-**Sub-agent trust defaults + delegate_tasks gate** (`cmd/odek/subagent.go`, `internal/loop/loop.go`) — a missing `trust_level` in `delegate_tasks` defaults to `untrusted`; `delegate_tasks` itself is classified as `system_write` so it requires explicit approval before spawning child processes.
181
+
-**Skill learn-loop provenance propagation** (`internal/skills/learnloop.go`) — conversation-extracted suggestions and LLM-enhanced suggestions both retain the session's `SkillProvenance`, so tainted sessions cannot produce clean-looking auto-saved skills.
181
182
-**Session ID entropy + session-scoped auth tokens** (`internal/session/session.go`, `cmd/odek/serve.go`) — session IDs now carry 128 bits of randomness (16 bytes / 32 hex chars); each session stores a 256-bit `AuthToken` required by `GET/DELETE/POST /api/sessions/<id>`, `POST /api/cancel`, and WebSocket session-resume messages via `X-Session-Token` header, `session_token` cookie, or `auth_token` WS field. Per-IP rate limiting (60/min) on session lookups adds a brute-force backstop.
182
183
-**Skill/episode untrusted wrapper** (`internal/loop/loop.go` + `odek.go`) — skill context and retrieved session-episode context are passed through the caller-provided untrusted wrapper (the same nonce'd `<untrusted_content_*>` boundary used for tool output) before being injected into the model's system context. This prevents a compromised or tainted skill/episode from being treated as trusted system instructions.
183
184
-**`env` / `printenv` environment-dump gate** (`internal/danger/classifier.go`) — bare `env` and `printenv` invocations are classified as `system_write` because they can leak process-environment secrets that the redaction scanner does not recognise. `env VAR=value <cmd>` still classifies `<cmd>` normally.
Copy file name to clipboardExpand all lines: docs/SECURITY.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -589,6 +589,15 @@ Now:
589
589
-`cmd/odek/subagent.go::applySubagentTrust` treats a missing `trust_level` as `untrusted`, forcing `non_interactive: deny` and denying Destructive/CodeExecution/Install/SystemWrite/NetworkEgress/Unknown/Blocked.
590
590
-`internal/loop/loop.go::classifyToolCall` classifies `delegate_tasks` as `system_write`, so spawning sub-agents requires explicit operator approval and cannot be used to escape the parent's approval gate.
591
591
592
+
### 39h. Skill learn-loop provenance propagation
593
+
594
+
Pattern-detected suggestions in `internal/skills/learnloop.go` were tagged with `DeriveProvenance`, but conversation-extracted suggestions (`ExtractSkillsFromConversation`) were appended without provenance, and the LLM enhancement step (`GenerateSkillWithLLM`) replaced the whole `SkillSuggestion` with the LLM-generated version, dropping the provenance. A tainted session could therefore produce a clean-looking auto-saved skill.
595
+
596
+
Now:
597
+
598
+
- Conversation-extracted suggestions receive the session provenance before being added to the suggestion list.
599
+
- The enhancement loop copies the original suggestion's `Provenance` onto the LLM-enhanced result, so `IsTainted()` remains true and `AutoSaveSuggestions` declines the skill unless `allowUntrusted` is set.
600
+
592
601
### 40. `/api/resources` result limit cap
593
602
594
603
The `/api/resources?q=...&limit=N` autocomplete endpoint previously accepted any positive `limit` value. It is now capped to 100 results both in the HTTP handler and in `Registry.Search`. This prevents a prompt-injected or attacker-forged request from forcing an unbounded directory walk and returning a multi-megabyte JSON response.
t.Errorf("verbose output should mention Quality gate failed for empty-body suggestion, got:\n%s", buf.String())
133
134
}
134
135
}
136
+
137
+
// validLLMSkillResponse returns the exact format GenerateSkillWithLLM and
138
+
// ExtractSkillsFromConversation expect, with a body long enough to pass the
139
+
// quality gate.
140
+
funcvalidLLMSkillResponse(namestring) string {
141
+
returnfmt.Sprintf(`NAME: %s
142
+
DESCRIPTION: A test skill
143
+
TOPICS: test, ci
144
+
ACTIONS: create, run
145
+
BODY:
146
+
## Overview
147
+
This is a test skill body with enough padding to exceed the two hundred character minimum required by the quality gate. Keep typing filler words until we are safely over the limit for sure.
148
+
149
+
## Step-by-Step
150
+
1. Do the thing
151
+
152
+
## Common Pitfalls
153
+
- Nothing
154
+
155
+
## Verification
156
+
- Check output
157
+
`, name)
158
+
}
159
+
160
+
// TestAnalyzeMessages_PreservesProvenanceThroughEnhancement verifies that
161
+
// LLM-enhanced suggestions keep the provenance derived from the session, so
162
+
// tainted sessions cannot produce clean-looking auto-saved skills.
0 commit comments