security: remediate top-10 audit findings (Phase A landed; Phase B in progress)#152
Merged
Conversation
TOTP setup/confirm now use pyotp for verification and qrcode[pil] for provisioning-URI rendering. Declare both as runtime deps and install them in the CI test job so the auth TOTP suite runs there. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…etup (C1) /api/auth/totp/setup and /confirm now require a verified biometric session (401 otherwise), closing the takeover path where an unauthenticated caller could enroll their own TOTP secret. The server now owns the enrollment secret end-to-end: setup stashes the pending secret in the in-memory session only (never written to disk via _save_sessions), and confirm ignores any client-supplied secret, verifying the code against the session-stashed pending secret before clearing it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The plaintext fallback writer (headless / Keychain-unavailable path) now uses codec_jsonstore.atomic_write_json: unique tmp -> flush -> os.fsync -> atomic replace -> 0600. A crash mid-write can no longer truncate or corrupt oauth_state.json. Durability-only change: no schema change, and the Keychain-primary path is untouched. Only the on-disk fallback gains the fsync guarantee. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the _SKIP_SKILLS denylist with a BRIDGE_SAFE_SKILLS allowlist so try_skill fails closed: a skill must be explicitly listed to run from an outbound bridge. iMessage is_sender_allowed and Telegram is_chat_allowed now fail closed when no allowlist is configured (with a one-time warning) instead of accepting every sender/chat. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… reads (C3) Remove python_exec from CHAT_SKILL_ALLOWLIST and drop its [SKILL:python_exec:...] prompt example so no chat message (injection or otherwise) can auto-fire arbitrary code execution. SKILL_MCP_EXPOSE=False already keeps it off MCP. Tighten the sandbox profile: layer targeted (deny file-read* ...) rules after the broad (allow file-read*) (SBPL last-match-wins) to block reads of ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, the Keychain dirs, and the ~/.codec secret / oauth_state files. The broad allow is intentionally retained so legitimate stdlib / site-packages imports keep working; config.json is intentionally NOT denied because sandboxed skills import codec_config at load (its secrets are Keychain-backed since PR-2B). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 29, 2026
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.
Remediation of the top-10 findings from the 2026-05-28 CODEC code audit. Design doc:
docs/SECURITY-REMEDIATION-DESIGN.md(+ follow-on notesdocs/FIX8-…,docs/FIX9-…, registrydocs/STATE-FILES.md).Durable home for the work (the local mirror auto-resets
maintoorigin/maindaily, so this is a pushed feature branch + PR). All changes TDD'd; 490 tests green across touched modules.Landed
Phase A — critical blockers
7a959523ecf6ed1685ebc1f3f2ab79c3518Phase B/C — robustness, correctness, hardening, structure
341a3b4run_with_timeout; kill hanging ThreadPoolExecutor (mcp/observer)2f23439b7c0055c465f9906da8f1dfe010d20e394bScope notes (partial fixes — follow-on documented)
routes/chat.pymodule split is deferred —chat_completionshares_load_prompt_overrides+CHAT_SYSTEM_PROMPTwith the prompt-override endpoints, so a clean split needs those relocated first (circular-import). Seedocs/FIX8-….pending_questions/grants), Phase 4 (don't-touch files) tracked indocs/STATE-FILES.md.Not started (needs you)
Reviewer notes
os.fsync), no schema change, Keychain path untouched.allow file-read*+ layered(deny …)after it (SBPL last-match-wins) to avoid breaking stdlib imports.🤖 Generated with Claude Code