You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
api(tasks): claim_task reassigns a pre-assigned task to any caller, overriding delegator intent #468
claim_task authorizes against the request body, not the stored row. The handler only checks the N13 body binding auth == body.assignee_did (crates/gitlawb-node/src/api/tasks.rs:175), then db.claim_task sets assignee_did=$2 on any pending row unconditionally (crates/gitlawb-node/src/db/mod.rs:3743-3757):
UPDATE agent_tasks SET status='claimed', assignee_did=$2, updated_at=$3WHERE id=$1AND status='pending'
complete_task/fail_task (tasks.rs:224, :277) then authorize against the stored assignee, so the new assignee of record passes them.
Impact
A signed caller other than the delegator's chosen assignee can take over a pending pre-assigned task and then legitimately complete or fail it. The schema (db/mod.rs:626-644) has no trigger or constraint preventing reassignment. Read-side exposure of the same objects is tracked in #268 and #395; this is the write-side ACL gap with a different root cause (N13 bound the caller to the body, never to the stored row).
Remediation
Extend the claim predicate: AND (assignee_did IS NULL OR assignee_did = $2).
Return 403 (or 409) when a pre-assigned pending task is claimed by another identity.
Integration test: a third-DID claim of a pre-assigned pending task must fail and not mutate the row.
Already covered by open PR #275, which implements this fix: claim admits only the reserved assignee or first claimer on open tasks, the UPDATE re-checks the assignee slot, and finish_task binds the stored assignee in SQL. Closing as covered there.
Activity
beardthelion commentedon Sep 26, 2026
Already covered by open PR #275, which implements this fix: claim admits only the reserved assignee or first claimer on open tasks, the UPDATE re-checks the assignee slot, and finish_task binds the stored assignee in SQL. Closing as covered there.