RUSTSEC-2026-0176 surfaced today on edge's cargo deny lane (v2.1.1 PR #88): pyo3 0.28's BoundListIterator::nth / BoundTupleIterator::nth / nth_back compute index + n with unchecked usize arithmetic, then read via get_item_unchecked. A sufficiently large n can wrap → out-of-bounds read.
Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0176
PyO3 fix: PyO3/pyo3#6086 (landed in 0.29.0)
Solution per RustSec: Upgrade to >=0.29.0 (try cargo update -p pyo3)
Edge's exposure
Grep across src/ confirms edge does NOT call .nth(/nth_back( on any PyO3 iterator path. The exposure is transitive-only (advisory fires on the dep graph; no edge code path triggers the vulnerability). Same posture as the other ignored advisories in deny.toml.
v2.1.1 ignores this in deny.toml with a tracking comment pointing here.
Why a lockstep upgrade
The whole CIRIS substrate family is on pyo3 0.28:
ciris-persist v5.5.0 — pyo3 0.28
ciris-verify-core v5.1.0 — pyo3 0.28
ciris-keyring / ciris-crypto v5.1.0 — pyo3 0.28
ciris-edge v2.1.1 — pyo3 0.28
ciris-lens-core v1.0.0 — pyo3 0.28 (transitive)
Edge moving alone would put pyo3 0.28 + pyo3 0.29 simultaneously in the cohabitation graph. Each cdylib statically bundles its own pyo3, so symbol-level it works, but cross-cdylib PyCapsule extraction relies on opaque pointer + name-tag stability — a mixed-version graph risks subtle ABI drift between the two PyO3 ffi tables.
Cleanest path: move persist + verify-family + edge + lens-core in lockstep, same pattern as the v5 keyring/crypto bump.
Migration surface (PyO3 0.28 → 0.29)
Per PyO3 0.29 release notes, the load-bearing changes for edge are:
- Bound API stabilization on a few iter methods (the fix itself)
- Minor signature changes on
PyAny::call* family
- Removal of some 0.27-deprecated paths (likely already-migrated in edge)
Most edge code is on the Bound API since the v0.10.0 capsule cycle; the bump is expected to be small-surface.
Suggested sequencing
- Persist + verify-family release pyo3-0.29 patch versions (5.6.0 / 5.2.0)
- Edge bumps deps + Cargo dep on pyo3 → 0.29 + Bound API touch-ups
- lens-core bumps in lockstep
- deny.toml ignore lifts
Not blocking the v2.1.1 critical path (Windows wheel + agent 2.9.6 substrate floor); ignore the advisory now, fold the upgrade into v2.2.0 once the upstream substrate moves.
cc CIRISPersist (substrate-side mover), CIRISVerify (crypto/keyring lockstep), CIRISLensCore (downstream catchup).
RUSTSEC-2026-0176 surfaced today on edge's
cargo denylane (v2.1.1 PR #88): pyo3 0.28'sBoundListIterator::nth/BoundTupleIterator::nth/nth_backcomputeindex + nwith uncheckedusizearithmetic, then read viaget_item_unchecked. A sufficiently largencan wrap → out-of-bounds read.Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0176
PyO3 fix: PyO3/pyo3#6086 (landed in 0.29.0)
Solution per RustSec:
Upgrade to >=0.29.0 (try cargo update -p pyo3)Edge's exposure
Grep across
src/confirms edge does NOT call.nth(/nth_back(on any PyO3 iterator path. The exposure is transitive-only (advisory fires on the dep graph; no edge code path triggers the vulnerability). Same posture as the other ignored advisories indeny.toml.v2.1.1 ignores this in
deny.tomlwith a tracking comment pointing here.Why a lockstep upgrade
The whole CIRIS substrate family is on pyo3 0.28:
ciris-persistv5.5.0 — pyo3 0.28ciris-verify-corev5.1.0 — pyo3 0.28ciris-keyring/ciris-cryptov5.1.0 — pyo3 0.28ciris-edgev2.1.1 — pyo3 0.28ciris-lens-corev1.0.0 — pyo3 0.28 (transitive)Edge moving alone would put pyo3 0.28 + pyo3 0.29 simultaneously in the cohabitation graph. Each cdylib statically bundles its own pyo3, so symbol-level it works, but cross-cdylib PyCapsule extraction relies on opaque pointer + name-tag stability — a mixed-version graph risks subtle ABI drift between the two PyO3 ffi tables.
Cleanest path: move persist + verify-family + edge + lens-core in lockstep, same pattern as the v5 keyring/crypto bump.
Migration surface (PyO3 0.28 → 0.29)
Per PyO3 0.29 release notes, the load-bearing changes for edge are:
PyAny::call*familyMost edge code is on the Bound API since the v0.10.0 capsule cycle; the bump is expected to be small-surface.
Suggested sequencing
Not blocking the v2.1.1 critical path (Windows wheel + agent 2.9.6 substrate floor); ignore the advisory now, fold the upgrade into v2.2.0 once the upstream substrate moves.
cc CIRISPersist (substrate-side mover), CIRISVerify (crypto/keyring lockstep), CIRISLensCore (downstream catchup).