Description
The Assessment History block on a person profile's History tab (RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs) has a data-integrity bug when the page's PersonId parameter is passed as a hashed IdKey rather than a plain integer:
- It filters correctly when
PersonId is a plain integer.
- It shows every
Assessment record in the entire database — attributed to whoever's profile happens to be open — when PersonId is an IdKey instead.
- This is internal-facing only: it affects staff viewing the person profile's History tab in the Rock admin, not the attendee-facing public profile page, which appears to correctly filter by
CurrentPerson rather than relying on an Id/IdKey page parameter. Assessment results are not exposed to the wrong person externally.
- The practical impact we've seen is staff seeing a person's profile appear to have a large number of pending assessment requests piled up, which reads as though the system is bombarding that attendee with repeated assessment requests — when in reality most or all of those "pending" rows belong to other people entirely and the attendee has no idea any of this is happening.
Root cause (confirmed against source, RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs, BindGrid(), lines 233–238 in both the 19.3.4 and 19.4.2-beta tags):
var personId = PageParameter( PageParameterKey.PersonId ).AsIntegerOrNull();
if ( personId.HasValue )
{
query = query.Where( a => a.PersonAlias.PersonId == personId.Value );
}
AsIntegerOrNull() returns null when PersonId arrives as a hashed IdKey string rather than an integer. Because personId.HasValue is then false, the surrounding if block is skipped and no .Where() filter is ever applied to the query — it falls through and returns the full, unfiltered Assessment table, which then gets bound to the grid as if it belonged to the current person.
Permalink to the exact lines on the 19.4.2-beta tag: https://github.com/SparkDevNetwork/Rock/blob/19.4.2-beta/RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs#L233-L238
For reference, develop has already replaced this block with a new Obsidian version (Rock.Blocks/Crm/AssessmentHistory.cs, added in commit ec0d1d91d9) that resolves PersonId via PersonService.GetSelect(personKey, selector, allowIntegerIdentifier), which is IdKey-aware. That rewrite isn't in a released 19.3.x/19.4.x tag yet, so it's worth confirming whether it actually fixes this specific failure mode or whether it needs the same null-check treatment.
A cursory search of open and closed issues did not turn up an exact duplicate. #4114 covers a related-sounding but distinct problem (orphaned assessment attributes after a person merge) — different root cause, not the same bug.
Actual Behavior
When the PersonId page parameter on the History tab is an IdKey instead of an integer, the Assessment History block's person filter is silently skipped, and the grid displays every assessment request in the system under whoever's profile is currently being viewed in the staff-facing admin.
Reliably reproducible — confirmed against the actual source of RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs as shipped in the 19.3.4 and 19.4.2-beta tags, and reproduced on the demo site (19.3) and on LCBC's own Rock environment.
Expected Behavior
The Assessment History block should resolve PersonId the same way whether it's passed as an integer or as an IdKey (e.g., using an IdKey-aware lookup such as PersonService.GetSelect), and should never fall back to an unfiltered query just because the parameter didn't parse as a plain integer.
Steps to Reproduce
- On the demo site, search for and open Cindy Decker's person profile. Confirm the URL uses an integer
PersonId (e.g. /Person/7).
- On Cindy's profile, use the Actions button → Request Assessment, select one or more assessments (e.g. DISC, Spiritual Gifts), and submit the request.
- If the environment has no communication transport/SMTP configured, the request will end on a "Workflow Processing Error(s): The SMTP host was not specified" page — this is expected and unrelated to the bug.
- Go to Cindy's profile History tab (More → History) and confirm the requested assessment(s) appear in the Assessment History block with a status of Pending, correctly attributed to Cindy.
- Use the family-member switcher (the name dropdown at the top-left of the profile) to switch to one of Cindy's family members, e.g. Ted Decker. Confirm the URL now shows Ted's own integer
PersonId.
- On Ted's History tab, confirm the Assessment History block correctly shows no assessments for Ted ("No Assessments Found") — the block behaves correctly here, because
PersonId is still an integer.
- While still on Ted's profile, use the admin toolbar to add an HTML block to a zone, and set its content to
<div>{{ Person.Id | ToIdHash }}</div>. Since Ted is the person in context, this renders Ted's own PersonId as its IdKey equivalent.
- Note the IdKey value rendered by the block above — this is Ted's own identifier, just hashed instead of a plain integer.
- Replace the integer
PersonId page parameter in Ted's own profile URL with that IdKey value from step 8 (i.e., load Ted's History tab, but pass his own IdKey as the PersonId parameter instead of his own integer id).
- Observe that the Assessment History block now displays Cindy's pending assessments — and, per the confirmed source, every other assessment in the database — as if they belong to Ted, even though the parameter used was Ted's own valid identity, because
AsIntegerOrNull() failed to parse the IdKey and the person filter was skipped entirely.
Note: this isn't limited to viewing someone else's page with their IdKey. Swapping in Cindy's own IdKey for her own integer PersonId on her own profile would trigger the same failure and surface every assessment in the system on her History tab too.
Reliably reproducible on the public demo site (rock.rocksolidchurchdemo.com) as well as on LCBC's own Rock instances, and the root cause above is confirmed directly against the shipped source for both versions.
Issue Confirmation
Rock Version
19.3, 19.4
Client Culture Setting
en-US
Description
The Assessment History block on a person profile's History tab (
RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs) has a data-integrity bug when the page'sPersonIdparameter is passed as a hashed IdKey rather than a plain integer:PersonIdis a plain integer.Assessmentrecord in the entire database — attributed to whoever's profile happens to be open — whenPersonIdis an IdKey instead.CurrentPersonrather than relying on an Id/IdKey page parameter. Assessment results are not exposed to the wrong person externally.Root cause (confirmed against source,
RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs,BindGrid(), lines 233–238 in both the19.3.4and19.4.2-betatags):AsIntegerOrNull()returnsnullwhenPersonIdarrives as a hashed IdKey string rather than an integer. BecausepersonId.HasValueis thenfalse, the surroundingifblock is skipped and no.Where()filter is ever applied to the query — it falls through and returns the full, unfilteredAssessmenttable, which then gets bound to the grid as if it belonged to the current person.Permalink to the exact lines on the
19.4.2-betatag: https://github.com/SparkDevNetwork/Rock/blob/19.4.2-beta/RockWeb/Blocks/Crm/AssessmentHistory.ascx.cs#L233-L238For reference,
develophas already replaced this block with a new Obsidian version (Rock.Blocks/Crm/AssessmentHistory.cs, added in commitec0d1d91d9) that resolvesPersonIdviaPersonService.GetSelect(personKey, selector, allowIntegerIdentifier), which is IdKey-aware. That rewrite isn't in a released 19.3.x/19.4.x tag yet, so it's worth confirming whether it actually fixes this specific failure mode or whether it needs the same null-check treatment.A cursory search of open and closed issues did not turn up an exact duplicate. #4114 covers a related-sounding but distinct problem (orphaned assessment attributes after a person merge) — different root cause, not the same bug.
Actual Behavior
When the
PersonIdpage parameter on the History tab is an IdKey instead of an integer, the Assessment History block's person filter is silently skipped, and the grid displays every assessment request in the system under whoever's profile is currently being viewed in the staff-facing admin.Reliably reproducible — confirmed against the actual source of
RockWeb/Blocks/Crm/AssessmentHistory.ascx.csas shipped in the19.3.4and19.4.2-betatags, and reproduced on the demo site (19.3) and on LCBC's own Rock environment.Expected Behavior
The Assessment History block should resolve
PersonIdthe same way whether it's passed as an integer or as an IdKey (e.g., using an IdKey-aware lookup such asPersonService.GetSelect), and should never fall back to an unfiltered query just because the parameter didn't parse as a plain integer.Steps to Reproduce
PersonId(e.g./Person/7).PersonId.PersonIdis still an integer.<div>{{ Person.Id | ToIdHash }}</div>. Since Ted is the person in context, this renders Ted's ownPersonIdas its IdKey equivalent.PersonIdpage parameter in Ted's own profile URL with that IdKey value from step 8 (i.e., load Ted's History tab, but pass his own IdKey as thePersonIdparameter instead of his own integer id).AsIntegerOrNull()failed to parse the IdKey and the person filter was skipped entirely.Note: this isn't limited to viewing someone else's page with their IdKey. Swapping in Cindy's own IdKey for her own integer
PersonIdon her own profile would trigger the same failure and surface every assessment in the system on her History tab too.Reliably reproducible on the public demo site (rock.rocksolidchurchdemo.com) as well as on LCBC's own Rock instances, and the root cause above is confirmed directly against the shipped source for both versions.
Issue Confirmation
Rock Version
19.3, 19.4
Client Culture Setting
en-US