Follow-up from PR #351 (which closes the spp.program.membership PII grant for scoring viewers). This is a separate, pre-existing sink on spp.scoring.result that PR #351 does not touch and should be triaged on its own.
Finding
A pure spp_scoring.group_scoring_viewer (no program/registry role) can read registrant PII directly from every scoring result:
- ACL grants the viewer read on
spp.scoring.result — spp_scoring/security/ir.model.access.csv (access_spp_scoring_result_viewer, 1,0,0,0).
- The record rule is unfiltered —
spp_scoring/security/rules.xml:46-53 rule_scoring_result_read_all domain_force = [(1, '=', 1)] for group_scoring_viewer → all results, not scoped to the viewer's area/programs.
spp_scoring/models/scoring_result.py:130-134: registrant_name = fields.Char(related="registrant_id.name", store=True) — stored, so the viewer reads the name of every scored registrant with no res.partner access needed.
scoring_result.py:91-97: inputs_snapshot / breakdown_json are JSON blobs of the field values used at scoring time. Indicators pull from res.partner (scoring_indicator.py), so these can contain arbitrary registrant field values (income, address, demographics — whatever indicators reference) for every scored registrant.
registrant_id (M2o res.partner) is also readable; whether it dereferences to full partner PII depends on the base res.partner ACL + OpenSPP global partner rules (area rule no-ops for a user with no assigned area) — flagged as likely-open, not confirmed.
Net: a scoring viewer obtains name + score + classification for all scored registrants, and potentially arbitrary snapshotted field values — without any program/registry role.
Severity: Medium
Authenticated-internal-user PII disclosure across all scored registrants; no privilege beyond the scoring-viewer role. Impact scales with how many registrants have been scored and which fields indicators reference.
Suggested fix (needs design decision)
- Scope
rule_scoring_result_read_all for group_scoring_viewer to the viewer's area/assigned scope (or to results they are entitled to), rather than [(1,'=',1)]; and/or
- restrict PII-bearing fields (
registrant_name, inputs_snapshot, breakdown_json, registrant_id dereference) from the pure-viewer surface via field-level groups or a redacted summary view.
Source: observed at spp_scoring/models/scoring_result.py:130 / spp_scoring/security/rules.xml:46 while staff-reviewing PR #351. Related: #351.
Follow-up from PR #351 (which closes the
spp.program.membershipPII grant for scoring viewers). This is a separate, pre-existing sink onspp.scoring.resultthat PR #351 does not touch and should be triaged on its own.Finding
A pure
spp_scoring.group_scoring_viewer(no program/registry role) can read registrant PII directly from every scoring result:spp.scoring.result—spp_scoring/security/ir.model.access.csv(access_spp_scoring_result_viewer,1,0,0,0).spp_scoring/security/rules.xml:46-53rule_scoring_result_read_alldomain_force = [(1, '=', 1)]forgroup_scoring_viewer→ all results, not scoped to the viewer's area/programs.spp_scoring/models/scoring_result.py:130-134:registrant_name = fields.Char(related="registrant_id.name", store=True)— stored, so the viewer reads the name of every scored registrant with nores.partneraccess needed.scoring_result.py:91-97:inputs_snapshot/breakdown_jsonare JSON blobs of the field values used at scoring time. Indicators pull fromres.partner(scoring_indicator.py), so these can contain arbitrary registrant field values (income, address, demographics — whatever indicators reference) for every scored registrant.registrant_id(M2ores.partner) is also readable; whether it dereferences to full partner PII depends on the baseres.partnerACL + OpenSPP global partner rules (area rule no-ops for a user with no assigned area) — flagged as likely-open, not confirmed.Net: a scoring viewer obtains name + score + classification for all scored registrants, and potentially arbitrary snapshotted field values — without any program/registry role.
Severity: Medium
Authenticated-internal-user PII disclosure across all scored registrants; no privilege beyond the scoring-viewer role. Impact scales with how many registrants have been scored and which fields indicators reference.
Suggested fix (needs design decision)
rule_scoring_result_read_allforgroup_scoring_viewerto the viewer's area/assigned scope (or to results they are entitled to), rather than[(1,'=',1)]; and/orregistrant_name,inputs_snapshot,breakdown_json,registrant_iddereference) from the pure-viewer surface via field-level groups or a redacted summary view.Source: observed at
spp_scoring/models/scoring_result.py:130/spp_scoring/security/rules.xml:46while staff-reviewing PR #351. Related: #351.