Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/audits/PHASE-1-CONSOLIDATED-TRIAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ If you do all 8: you have layered defenses against D-1 / D-2 / D-3 / D-4 / D-7 u
| **D-1** | Security | Skill registry lazy-load = RCE for anyone who can drop a `.py` file | **W1 β€” CLOSED ([#42](https://github.com/AVADSA25/codec/pull/42), `48ec5d5`)** |
| **D-2** | Security | `/api/forge` fetches arbitrary URL β†’ LLM β†’ writes skill, no review gate | **W1 β€” CLOSED ([#43](https://github.com/AVADSA25/codec/pull/43), `ff16664`)** |
| **D-3** | Security | `/api/save_skill` writes directly to skills/ with only substring check | **W1 β€” CLOSED ([#43](https://github.com/AVADSA25/codec/pull/43), `ff16664`)** |
| **D-4** | Security | `file_write` skill (MCP-exposed) can write to `~/.codec/skills/` | **W1 β€” CLOSED (PR-1C)** |
| **D-4** | Security | `file_write` skill (MCP-exposed) can write to `~/.codec/skills/` | **W1 β€” CLOSED ([#45](https://github.com/AVADSA25/codec/pull/45), `0065d90`)** |
| **D-5** | Security | `permission_gate` accepts path-traversal via `fnmatch` (no realpath) | **W1** |
| C-1 | Reliability | `codec.py` daemon ignores SIGINT/SIGTERM; leaks sox + tkinter on every restart | W4 |
| C-2 | Reliability | `~/.codec/pwa_response.json` race conditions + no correlation_id | W4 |
Expand Down
2 changes: 1 addition & 1 deletion docs/audits/PHASE-1-SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ No human review gate. No `/api/skill/review` staging. `is_dangerous_skill_code`'
**Location:** `skills/file_write.py` (`SKILL_MCP_EXPOSE = True`) + `codec_config.py:_HTTP_BLOCKED` (file_write NOT blocked on HTTP)
**CWE / OWASP:** CWE-22 Path Traversal / OWASP A01 Broken Access Control / Agentic A02 Tool Misuse

> **Closed by PR-1C** (branch `fix/pr1c-file-write-block-roots`). `skills/file_write.py:_is_safe_target` was refactored to (1) realpath the blocklist at module load so macOS `/etc β†’ /private/etc` aliases are caught regardless of which name the caller uses, (2) block the entire `~/.codec/` tree (covers skills, plugins, oauth_state.json, audit.log, config.json, memory.db, agents/, notifications.json, pending_questions.json, agent_global_grants.json, triggers_killed.json β€” every security-sensitive file at once), (3) block `<repo>/skills/` so the built-in skill directory can't be tampered with. Pre-existing bug also fixed: `/tmp` writes were silently failing because realpath resolves to `/private/tmp` and the old code hard-coded `/private` as a blocked root; now `/tmp` and `~` are both realpath-resolved in the sanity check. Defense in depth pairs with PR-1A's load-time gate. 21 tests in `tests/test_file_write.py` cover blocked-path refusal (incl. symlink resolution) and regression on legitimate paths (`~/Documents`, `~/Desktop`, `/tmp`, `~/Projects`, `~/codec-workspace`).
> **Closed by PR-1C** ([#45](https://github.com/AVADSA25/codec/pull/45), merged as `0065d90`). `skills/file_write.py:_is_safe_target` was refactored to (1) realpath the blocklist at module load so macOS `/etc β†’ /private/etc` aliases are caught regardless of which name the caller uses, (2) block the entire `~/.codec/` tree (covers skills, plugins, oauth_state.json, audit.log, config.json, memory.db, agents/, notifications.json, pending_questions.json, agent_global_grants.json, triggers_killed.json β€” every security-sensitive file at once), (3) block `<repo>/skills/` so the built-in skill directory can't be tampered with. Pre-existing bug also fixed: `/tmp` writes were silently failing because realpath resolves to `/private/tmp` and the old code hard-coded `/private` as a blocked root; now `/tmp` and `~` are both realpath-resolved in the sanity check. Defense in depth pairs with PR-1A's load-time gate. 21 tests in `tests/test_file_write.py` cover blocked-path refusal (incl. symlink resolution) and regression on legitimate paths (`~/Documents`, `~/Desktop`, `/tmp`, `~/Projects`, `~/codec-workspace`).
**Description:** `file_write` enforces `realpath` resolution + `_BLOCKED_ROOTS` (`/System`, `/Library`, `/etc`, etc.) + `_BLOCKED_FILENAME_PATTERNS` (`.ssh`, `.env`, `secret`, etc.) + `_BLOCKED_EXTS`. But `~/.codec/skills/<name>.py` is:
- Under `$HOME` (passes the home check at line 103).
- Does not start with any `_BLOCKED_ROOTS` after realpath.
Expand Down
Loading