Security hardening: fix high/medium/low findings (#50-#76)#42
Merged
Conversation
- Default non-interactive policy is now deny (was allow). - Strip project-level backend redirects: embedding, memory, sessions, skills.dirs/skills.embedding, telegram, web_search. - Protect all ~/.odek trust anchors from generic file-tool writes: sessions/, audit/, plans/, schedules.json, schedule-state.json, mcp_approvals.json, mcp_tool_approvals.json, restart.json, telegram.lock, telegram.pid, schedule.pid, schedule.log. - Add field-by-field skills overlay so project skills settings do not clobber global dirs/embedding. - Update docs (SECURITY.md, CONFIG.md, CLI.md, AGENTS.md) and add regression tests.
- #66: shell reads of ~/.odek trust anchors now classify as system_write - #65: bare env/printenv environment dumps classify as system_write - #70: Web UI file attachments wrapped as untrusted before prompt injection - #56: per-instance random CSRF token required for /ws upgrades - token injected into index.html meta tag and HttpOnly SameSite=Strict cookie - accepted via cookie, X-Odek-Ws-Token header, or odek.<token> subprotocol - added regression tests and updated SECURITY.md / AGENTS.md
- #67: scan explicit --system / ODEK_SYSTEM / config system prompts for injection threats and size; fall back to default identity on failure - #54: require session-scoped auth token for POST /api/cancel - pass store into handleCancel and validate via validateSessionToken - UI cancel fetch now sends X-Session-Token header - updated all cancel tests to authenticate, plus added 401 regression test - updated SECURITY.md and AGENTS.md
- #62: cap Telegram plan files at 1 MiB for ReadPlan/MostRecentPlan; list previews read only first 8 KiB - #75: verify outbound media final component with atomic O_NOFOLLOW open + fstat on Unix to close symlink TOCTOU race - #76: create Telegram log files with 0600 and chmod existing files - added regression tests and updated SECURITY.md / AGENTS.md
- docs/TELEGRAM.md: document plan size cap, O_NOFOLLOW media verification, and 0600 log file permissions - internal/telegram/plan_test.go: add at-cap, MostRecentPlan oversize, and ListPlans preview tests - internal/telegram/media_path_test.go: add tilde expansion and symlink-to- allowed-file rejection tests - internal/telegram/log_test.go: add existing-file permission hardening test - full suite and race detector pass
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
odek | 30771c0 | Commit Preview URL Branch Preview URL |
Jun 17 2026, 06:53 PM |
Comment on lines
+1570
to
+1577
| http.SetCookie(w, &http.Cookie{ | ||
| Name: wsTokenCookieName, | ||
| Value: wsToken, | ||
| Path: "/", | ||
| SameSite: http.SameSiteStrictMode, | ||
| HttpOnly: true, | ||
| // No explicit MaxAge/Expires so the cookie is a session cookie. | ||
| }) |
… #79, #81 - cmd/odek/serve.go: server-side cap on WebSocket prompt size (1 MiB) and validation of model ID length/characters (#69, #81) - cmd/odek/subagent.go: parse and cap --timeout (<=3600s) and --max-iter (<=100) (#79) - internal/config/loader.go: refuse to load ~/.odek/secrets.env when it is group/world-readable (#78) - internal/telegram/health.go: warn when health server binds to a non-loopback address (#77) - Add regression tests for all fixes; full suite, race detector, go vet and golangci-lint pass
Contributor
Author
AI Verification Certificate — PR #42PR: #42 — Security hardening: fix high/medium/low findings (#50-#76)Repository: η Derivation
Skipped weights redistributed proportionally across η = 0.647 | ρ = 0.25 Axes Summary
Verification Debt Contribution
Auto-Applied Remediations (this VProtocol run)
All remediations include regression tests. Unverified Gaps
Test ResultsVerdict
Rationale (binding gates):
Most restrictive gate wins → Attestation
{
"certificate_id": "25a93d2d-d762-480b-bd9c-4f7d4a20b674",
"protocol_version": "5.2.7",
"pr": {
"number": 42,
"title": "Security hardening: fix high/medium/low findings (#50-#76)",
"repo": "BackendStack21/odek",
"sha": "30771c05036b42f51fceff3a112660be6d9985dc",
"loc_changed": 1803,
"oversized": false
},
"classification": "GeneratedCode",
"generator": {
"model": "Kimi Code CLI",
"version": "unknown",
"provider": "Moonshot AI",
"lineage_status": "not_provided"
},
"pipeline": {
"diversity_ok": false,
"diversity_notes": "All roles executed by the same Kimi instance; monoculture fallback applied."
},
"untrusted_input": {
"violation_detected": true,
"violation_excerpt": "Pre-scan found literal 'Ignore previous instructions' / '<!-- ignore previous instructions...' strings inside test fixtures (serve_test.go, main_test.go). Expected regression payloads, but force axis 2.8 to fail per §0 invariant."
},
"eta": {
"value": 0.647,
"signals": {
"m": null,
"o": null,
"b": 0.758,
"f": null,
"s": 1.0,
"t": 1.0,
"d": 1.0
},
"signals_skipped": ["m", "o", "f"],
"weights": {
"b": 0.424,
"s": 0.121,
"t": 0.303,
"d": 0.152
},
"weights_redistributed": true,
"rho": 0.25,
"rho_breakdown": {
"family": 0.10,
"version": 0.05,
"ast": 0.03,
"shared_mutants": 0.02,
"spec_independence": 0.05
},
"rederivation_attested": true
},
"axes": [
{"id": "2.1", "status": "pass"},
{"id": "2.2", "status": "warn"},
{"id": "2.3", "status": "warn"},
{"id": "2.4", "status": "pass"},
{"id": "2.5", "status": "warn"},
{"id": "2.6", "status": "pass"},
{"id": "2.7", "status": "warn"},
{"id": "2.8", "status": "fail"},
{"id": "2.9", "status": "pass"}
],
"debt": {
"delta_hours": 0.0,
"ci_dollars": 0.0,
"ci_estimated": true,
"ci_source": "not_provided",
"cv_dollars": 0.0,
"ratio": null,
"ratio_note": "Ci_zero"
},
"verdict": "HumanReviewRequired",
"rationale": "η=0.647 < 0.80; ρ=0.25 > 0.20; axis 2.8 fail from pre-scan injection strings in test fixtures; PR size ~1,803 LOC. Most restrictive gate wins."
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR addresses the security findings from
sec_findings.mdin priority order (high → medium → low), with expanded docs and regression tests.Fixed
High
non_interactivepolicy changed fromallowtodeny; explicitly require operator opt-in for unsupervised destructive/network/code-exec actions.~/.odektrust anchors:read_file,patch,write_file,batch_patch, and related perf/file tools block writes to~/.odek/IDENTITY.md,~/.odek/config.json, secrets files, schedules, sessions, and skill caches.system_write../odek.jsoncan no longer overridebase_url,api_key,system, or thedangeroussection.Medium
env/printenvclassified assystem_write.~/.odektrust-anchor files escalate tosystem_write.--ctxuploads are wrapped with a nonce'd<untrusted_content_*>boundary before injection into the prompt./wsendpoint now requires a per-instance random CSRF token (cookieodek_csrf+ headerX-CSRF-Tokenor WebSocket subprotocol).Low
--system/~/.odek/IDENTITY.mdprompts are scanned for injection patterns and fall back to the compiled-in default if oversized (>256 KiB) or suspicious.POST /api/cancelnow requires the session-scopedAuthToken.Telegram low findings
ResolveMediaPathverifies the final path component withO_NOFOLLOW+fstaton Unix to close the symlink TOCTOU window.0600; existing files are hardened viaos.Chmod.Test coverage
go test ./... -count=1go test -race ./internal/telegram/... ./cmd/odek/... ./internal/danger/... -count=1ODEK_E2E=true go test ./cmd/odek/ -run 'TestE2E_|TestMCPE2E_|TestSandbox' -count=1Not in scope
Remaining lower-priority findings (e.g. Web UI caps/rate limits, MCP per-connection spawn, sub-agent task path confinement, CSP hardening) are documented in
sec_findings.mdand can be addressed in follow-up PRs.