Page MenuHomePhabricator

Information leak and other bad stuff in SocialProfile's ApiUserProfilePrivacy
Closed, ResolvedPublicSecurity

Description

SocialProfile has had a feature allowing users to determine (on the Special:UpdateProfile page) who can see the contents of a user profile page field (like "Music", "TV", "Food", "Websites", etc.) since version 1.8/15 January 2015 (rESPR791a466c4e51c88b9aaad7fb45a8f0dde5de39cd).
Assuming you don't want everyone to know your favorite foods, for example, you can set that field to be visible to friends or friends of friends (foaf) or even entirely hidden (in which case it's visible only to you, though that's kinda silly and pointless).

The PHP backend for this feature is /extensions/SocialProfile/UserProfile/includes/SPUserSecurity.php and the buggy API module called by the JS code in /extensions/SocialProfile/UserProfile/resources/js/UpdateProfile.js is in /extensions/SocialProfile/UserProfile/includes/api/ApiUserProfilePrivacy.php.

It seems that you can not only get but also set field visibilities for another user when you know their user ID. Yes, the module has appropriate CSRF protections and no, it's obviously no substitute for proper "is the user even allowed to do this?" sorta permissions checking.

Test case -- get the current visibility of up_websites field (corresponding to the field with the same name in the user_profile table) for the user whose user ID is 1:

( new mw.Api() ).postWithToken( 'csrf', {
	action: 'smpuserprivacy',
	format: 'json',
	method: 'get',
	'field_key': 'up_websites',
	tuid: '1'
} ).done( function ( data ) {
	console.log( data );
} );

Test case -- set the up_websites field to be visible to everyone for the user whose user ID is 1:

( new mw.Api() ).postWithToken( 'csrf', {
	action: 'smpuserprivacy',
	format: 'json',
	method: 'set',
	'field_key': 'up_websites',
	tuid: '1',
	privacy: 'public'
} ).done( function ( data ) {
	console.log( data );
} );

Both queries can currently be run even as an anon and they return the correct data.

Slightly relatedly, I want to note that assuming that the user has only filled out the "Websites" (up_websites) section under the social profile section labeled "Personal information" and they choose to hide this field from the world, it still is somewhat obvious that something is hidden; if a section is entirely empty (e.g. the user hasn't supplied their websites or location or any other data under "Personal information"), it isn't rendered on the profile at all. But if one field has been filled out but is hidden from the world, the "Personal information" <h2> element gets output. (This is done in /extensions/SocialProfile/UserProfile/includes/UserProfilePage.php, function getPersonalInfo, specifically presumably due to the existence of the $joined_data variable which checks no visibilities whatsoever.)

Event Timeline

ashley created this task.Mar 24 2020, 12:07 PM
Restricted Application added a subscriber: Aklapper. · View Herald TranscriptMar 24 2020, 12:07 PM
Restricted Application added a project: Social-Tools. · View Herald TranscriptMar 24 2020, 12:08 PM
chasemp moved this task from Incoming to Watching on the Security-Team board.Mar 24 2020, 3:06 PM
chasemp added a subscriber: chasemp.

@ashley since you've got this task assigned to you, I'll move it to watching on our workboard. Thanks.

chasemp triaged this task as Medium priority.Mar 24 2020, 3:06 PM
ashley closed this task as Resolved.Jun 28 2020, 4:29 PM

Yeah, this was fixed back in March.

Legoktm changed the visibility from "Custom Policy" to "Public (No Login Required)".Jun 29 2020, 5:10 AM
Legoktm changed the edit policy from "Custom Policy" to "All Users".