Repository navigation
feat(wake): bound chained wakes with a hop limit and wake provenance #238
Description
What happened
Security and stability hardening audit finding H11 / P3 (2026-09-28). Priority is an audit recommendation, not a claim of a production incident.
A woken Codex turn can call session-peer again, through the shell or the MCP send_message tool with wake: true, and so wake another thread. The app-server environment passes only CODEX_HOME on top of the caller's environment. There is no wake depth, origin or hop count. The MCP adapter checks the wake capability and a 1-60 s timeout, but has no hop or rate limit.
Two mechanisms prevent the simplest recursion:
codex_wake_guardrefuses a concurrent wake of the same thread.- A thread that already has a live writer returns
already_activeinstead of being resumed.
Neither bounds a chain of distinct threads or hosts (A→B→C→…). Neither stops a queue-sustained loop either. Example: a live, unattended Codex session A processes its queue, wakes B on each turn, and B's woken turn replies to A.
With the documented non-interactive setting tools.send_message.approval_mode="approve", each hop can run a turn of up to 60 s, and every turn costs model usage. No human reviews any of these turns, and no component can see or cap how far the chain has gone.
What you expected
Wakes carry provenance and a bounded hop count, and session-peer refuses a wake past a default limit with a clear reason.
Environment
- Baseline: published session-peer v1.0.2, commit
2046836822b88e53246de73851186598604cb5ec. - Reproduction: source review only; no sessions were woken, no live message/ACK tests were run, and no production mutation was made.
- Audit environment: macOS arm64, Python 3.14.7.
- Discovery output: not applicable; no real session identifiers or credentials are included.
Source evidence
- session_peer_core/codex.py#L839-L848
- session_peer_core/codex.py#L901-L903
- session_peer_core/codex.py#L1006-L1013
- session_peer_mcp.py#L198-L203
- docs/mcp.md#L49
Acceptance criteria
- Wake sets a wake depth variable (for example
SESSION_PEER_WAKE_DEPTH) in the app-server environment. The CLI and MCP adapter read it and increment it for nested wakes. - A wake beyond a documented default limit is refused before queueing with
wake_depth_exceeded. Operators can lower the limit; raising it requires explicit configuration. - The envelope includes hop and wake-origin information, so that queue-mediated loops (where the environment does not carry the depth) are visible. A per-target wake rate limit is considered for these loops.
- Tests check whether the depth survives the Codex shell and MCP server environment policies, and document where it does not.
- Existing
wake_in_progress/already_activebehaviour is unchanged.
Scope and limitations
Codex may filter the environment passed to shell commands or MCP servers. Propagation through those layers has not been verified here and is an acceptance item.
Target: v1.1.0. This issue does not authorize a release or operating-service changes.
Related, not duplicate: #46 (introduced explicit wake), #184 (optional guard checkpoint for send and wake).
Checked
- Searched existing issues for duplicates.
- Removed credentials, conversation contents, private paths and real device/session identifiers.
- Used isolated fixtures without weakening inbound permissions.
Activity
abruption commentedon Oct 9, 2026
Final acceptance — 2026-10-09: closing as completed for v1.1.0 cooperative wake-chain safeguards, implemented by #288.
Depth/origin propagation and diagnostic provenance, bounded pre-queue refusal, per-target durable activation reservations, rollback/unsafe-state refusal and existing active/dry-run guards are implemented. Tagged
tests/codex/test_wake_chain.pycovers these contracts and typed SSH/MCP context. The PR also records two opt-in tests covering ten actual shell/MCP startup environment cases against the pinned macOS arm64 Codex 0.154.0 binary; absent binary means explicit skips, not native evidence from ordinary CI.Environment filtering can lose context and start a new origin; shared MCP startup context is not per-call identity. Rates are local per-home/target, not a global spend or unbreakable chain bound. No current/later Codex version, other-platform native/model wake, live remote routing, caller authentication or permission guarantee is asserted. These limitations meet the original requirement to investigate and document propagation boundaries.
Release evidence: v1.1.0, source
8ca77cf31254c8287a2593fe484bb30a7dba2727; exact integrated-main CI and PyPI publication/verification succeeded. Final acceptance rechecked tagged code/tests/docs and merged PR evidence; this final accounting did not rerun tests or perform new live messages, native wake, installations or operations.