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
Follow-up from the cross-PR interaction analysis of the open security PRs (2026-07-24). Surfaced while reviewing the #264 × #338 combination; the gap is pre-existing rather than created by merging, but neither PR closes it and #264 provides the natural mechanism to do so.
Finding
PR security(cr): route and apply the same single field for dynamic approvals #264 freezes the proposed change after a CR leaves draft/revision via _protected_content_fields on the detail base (spp_change_request_v2/models/change_request_detail_base.py). For the field_mapping apply strategy that set covers the payload; for the custom strategy used by spp_cr_type_assign_program it resolves to {"field_to_modify"} only.
The assign-program detail's actual payload is program_id — and it is not in the protected set. So after submission (and even after approval, before apply), the CR owner can still repoint program_id via RPC write.
PR security(cr): validate program access on assign-program detail #338 adds @api.constrains("program_id") guaranteeing the target program is accessible to the writer (record-rule visibility + company check) — but accessibility is not approval-fidelity: the approver approves assignment to program X, the owner repoints to accessible program Y, apply assigns Y.
Combined with #264 and #338 both merged, the remaining hole is exactly this post-submit repoint window.
Severity: Medium
Requires an authenticated CR user who owns the CR, and the substitute target must itself be accessible to them (#338). Impact: the approval record no longer matches what is applied — an approver's decision can be redirected to a different (visible, same-company) program without re-approval.
Suggested fix
spp_cr_type_assign_program overrides _protected_content_fields to add program_id (and any other payload fields of the custom strategy), reusing #264's freeze mechanism. Depends on #264 landing first.
Follow-up from the cross-PR interaction analysis of the open security PRs (2026-07-24). Surfaced while reviewing the #264 × #338 combination; the gap is pre-existing rather than created by merging, but neither PR closes it and #264 provides the natural mechanism to do so.
Finding
_protected_content_fieldson the detail base (spp_change_request_v2/models/change_request_detail_base.py). For thefield_mappingapply strategy that set covers the payload; for the custom strategy used byspp_cr_type_assign_programit resolves to{"field_to_modify"}only.program_id— and it is not in the protected set. So after submission (and even after approval, before apply), the CR owner can still repointprogram_idvia RPC write.@api.constrains("program_id")guaranteeing the target program is accessible to the writer (record-rule visibility + company check) — but accessibility is not approval-fidelity: the approver approves assignment to program X, the owner repoints to accessible program Y, apply assigns Y.Combined with #264 and #338 both merged, the remaining hole is exactly this post-submit repoint window.
Severity: Medium
Requires an authenticated CR user who owns the CR, and the substitute target must itself be accessible to them (#338). Impact: the approval record no longer matches what is applied — an approver's decision can be redirected to a different (visible, same-company) program without re-approval.
Suggested fix
spp_cr_type_assign_programoverrides_protected_content_fieldsto addprogram_id(and any other payload fields of the custom strategy), reusing #264's freeze mechanism. Depends on #264 landing first.Source:
internal/plans/security-prs-interaction-analysis.md(CR cluster review, 264×338). Related: #264, #338.