main · last commit
1 month ago ·
2npkec0r
tarantool-etcd-e3d [security] Txn nested Put ignores prev_kv READ check — RBAC bypass leaks values to WRITE-only grants
Lined Up
bd update tarantool-etcd-e3d --claim
bd close tarantool-etcd-e3d
| Created by | Eugene Blikh |
| Owner | bigbes@gmail.com |
| Created | 2026-07-17T13:18:42Z |
| Updated | 2026-07-17T13:18:42Z |
A user granted WRITE-only on a key can read its value via Txn{success=[Put(key, prev_kv=true)]}.
Verified by hand:
- app/etcd/auth.lua:313-314 — the nested-op permission walk does only 'M.require_permission(PERM_WRITE, op.request_put.key)' for request_put. No prev_kv READ check.
- The asymmetry proves it is an oversight, not a decision: the ADJACENT branch for request_delete_range (auth.lua:316-320) DOES check 'if r.prev_kv then require_permission(PERM_READ, ...)', and the top-level kv.M.put (app/etcd/kv.lua:561-563) does the same.
- The leak is client-observable: execution dispatches to put_internal, which populates the response — app/etcd/kv.lua:538-540 'if req.prev_kv and prev_kv then resp.prev_kv = prev_kv end'.
etcd runs full checkPutAuth on txn puts (server/etcdserver/apply/auth.go) — WRITE plus READ when prev_kv/ignore_value/ignore_lease is set. Same bug class upstream fixed as CVE-2026-33413 / CVE-2026-33343.
Second, separable defect in the same area: checkLeasePuts has no analogue anywhere. etcd denies attaching a lease when the caller cannot write the OTHER keys already on that lease; we only re-check on the revoke side (app/etcd/lease.lua:143). Neither the top-level nor the nested Put path sweeps the lease's key set.
Factor a single check_put_auth(key, prev_kv, lease) used by BOTH kv.M.put and auth.check_txn_ops so the two paths cannot drift again — the drift is what caused this. The lease-attach sweep is separable; split it out if it grows.
A WRITE-only user gets PermissionDenied for Txn{Put(prev_kv=true)} on both wires; the equivalent top-level Put still behaves as today; a Lua test in test/auth_test.lua pins the nested case specifically; lease-attach denial covered or split to its own issue.
No outgoing dependencies.
Nothing depends on this issue.
| id | tarantool-etcd-e3d |
| content_hash | 6ab01fc66074fb8cbaf998a242421bed2c095548c511728dcfc4fadf5803c22f |
| title | [security] Txn nested Put ignores prev_kv READ check — RBAC bypass leaks values to WRITE-only grants |
| description | A user granted WRITE-only on a key can read its value via Txn{success=[Put(key, prev_kv=true)]}. Verified by hand: - app/etcd/auth.lua:313-314 — the nested-op permission walk does only 'M.require_permission(PERM_WRITE, op.request_put.key)' for request_put. No prev_kv READ check. - The asymmetry proves it is an oversight, not a decision: the ADJACENT branch for request_delete_range (auth.lua:316-320) DOES check 'if r.prev_kv then require_permission(PERM_READ, ...)', and the top-level kv.M.put (app/etcd/kv.lua:561-563) does the same. - The leak is client-observable: execution dispatches to put_internal, which populates the response — app/etcd/kv.lua:538-540 'if req.prev_kv and prev_kv then resp.prev_kv = prev_kv end'. etcd runs full checkPutAuth on txn puts (server/etcdserver/apply/auth.go) — WRITE plus READ when prev_kv/ignore_value/ignore_lease is set. Same bug class upstream fixed as CVE-2026-33413 / CVE-2026-33343. Second, separable defect in the same area: checkLeasePuts has no analogue anywhere. etcd denies attaching a lease when the caller cannot write the OTHER keys already on that lease; we only re-check on the revoke side (app/etcd/lease.lua:143). Neither the top-level nor the nested Put path sweeps the lease's key set. |
| design | Factor a single check_put_auth(key, prev_kv, lease) used by BOTH kv.M.put and auth.check_txn_ops so the two paths cannot drift again — the drift is what caused this. The lease-attach sweep is separable; split it out if it grows. |
| acceptance_criteria | A WRITE-only user gets PermissionDenied for Txn{Put(prev_kv=true)} on both wires; the equivalent top-level Put still behaves as today; a Lua test in test/auth_test.lua pins the nested case specifically; lease-attach denial covered or split to its own issue. |
| notes | |
| status | open |
| priority | 0 |
| issue_type | bug |
| assignee | NULL |
| estimated_minutes | NULL |
| created_at | 2026-07-17T13:18:42Z |
| created_by | Eugene Blikh |
| owner | bigbes@gmail.com |
| updated_at | 2026-07-17T13:18:42Z |
| closed_at | NULL |
| closed_by_session | |
| external_ref | NULL |
| spec_id | |
| compaction_level | 0 |
| compacted_at | NULL |
| compacted_at_commit | NULL |
| original_size | NULL |
| sender | |
| ephemeral | 0 |
| wisp_type | |
| pinned | 0 |
| is_template | 0 |
| mol_type | |
| work_type | |
| source_system | |
| metadata | <binary> |
| source_repo | |
| close_reason | |
| event_kind | |
| actor | |
| target | |
| payload | |
| await_type | |
| await_id | |
| timeout_ns | 0 |
| waiters | |
| hook_bead | |
| role_bead | |
| agent_state | |
| last_activity | NULL |
| role_type | |
| rig | |
| due_at | NULL |
| defer_until | NULL |
| no_history | 0 |
| started_at | NULL |
| is_blocked | 0 |
| issue_id | tarantool-etcd-e3d |
| label | etcd-changelog-sweep |
| id | 019f703a-af67-78f8-98ad-dbdaa013770c |
| issue_id | tarantool-etcd-e3d |
| event_type | created |
| actor | Eugene Blikh |
| old_value | |
| new_value | |
| comment | NULL |
| created_at | 2026-07-17T16:18:42Z |
| id | 019f703a-af67-7eff-a11e-ca45b6b5039e |
| issue_id | tarantool-etcd-e3d |
| event_type | label_added |
| actor | Eugene Blikh |
| old_value | NULL |
| new_value | NULL |
| comment | Added label: etcd-changelog-sweep |
| created_at | 2026-07-17T16:18:42Z |
No comments.