Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2020-36754: Changeset 2368689 for paid-memberships-pro – WordPress Plugin Repository

The Paid Memberships Pro plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 2.4.2. This is due to missing or incorrect nonce validation on the pmpro_page_save() function. This makes it possible for unauthenticated attackers to save pages via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.

CVE
#sql#xss#vulnerability#ios#wordpress#php#auth

Legend:

Unmodified

Added

Removed

  • paid-memberships-pro/tags/2.4.3/CHANGELOG.txt

    r2368140

    r2368689

1

1

\== Changelog ==

 

2

\= 2.4.3 - 2020-08-25

 

3

\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)

 

4

\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.

 

5

\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.

 

6

2

7

\= 2.4.2 - 2020-08-24

3

8

\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
  • paid-memberships-pro/tags/2.4.3/includes/metaboxes.php

    r2098264

    r2368689

1

1

<?php

2

 

/\*

3

 

    Require Membership Meta Box

4

 

\*/

5

 

function pmpro\_page\_meta()

6

 

{

 

2

/\*\*

 

3

 \* Require Membership Meta Box

 

4

 \*/

 

5

function pmpro\_page\_meta() {

7

6

    global $post, $wpdb;

8

 

    $membership\_levels = pmpro\_getAllLevels(true, true);

9

 

    $page\_levels = $wpdb->get\_col("SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '{$post->ID}'");

 

7

    $membership\_levels = pmpro\_getAllLevels( true, true );

 

8

    $page\_levels = $wpdb->get\_col( "SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post->ID ) . "'" );

10

9

?>

11

10

    <ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">

12

 

    <input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) )?>" />

 

11

    <input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo esc\_attr( wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) ) )?>" />

13

12

    <?php

14

13

        $in\_member\_cat = false;

15

 

        foreach($membership\_levels as $level)

16

 

        {

17

 

    ?>

18

 

        <li id="membership-level-<?php echo $level->id?>">

 

14

        foreach( $membership\_levels as $level ) {

 

15

        ?>

 

16

        <li id="membership-level-<?php echo esc\_attr( $level->id ); ?>">

19

17

            <label class="selectit">

20

 

                <input id="in-membership-level-<?php echo $level->id?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo $level->id?>" />

 

18

                <input id="in-membership-level-<?php echo esc\_attr( $level->id ); ?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo esc\_attr( $level->id ) ;?>" />

21

19

                <?php

22

 

                    echo $level->name;

 

20

                    echo esc\_html( $level->name );

23

21

                    //Check which categories are protected for this level

24

 

                    $protectedcategories = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id");

 

22

                    $protectedcategories = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "'");

25

23

                    //See if this post is in any of the level's protected categories

26

 

                    if(in\_category($protectedcategories, $post->id))

27

 

                    {

 

24

                    if( in\_category( $protectedcategories, $post->id ) ) {

28

25

                        $in\_member\_cat = true;

29

26

                        echo ' \*';

…

…

 

32

29

            </label>

33

30

        </li>

34

 

    <?php

 

31

        <?php

35

32

        }

36

33

    ?>

37

34

    </ul>

38

35

    <?php

39

 

        if('post' == get\_post\_type($post) && $in\_member\_cat) { ?>

 

36

        if( 'post' == get\_post\_type( $post ) && $in\_member\_cat ) { ?>

40

37

        <p class="pmpro\_meta\_notice">\* <?php \_e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>

41

38

    <?php

42

39

        }

43

40

44

 

        do\_action('pmpro\_after\_require\_membership\_metabox', $post);

 

41

        do\_action( 'pmpro\_after\_require\_membership\_metabox', $post );

45

42

    ?>

46

43

<?php

47

44

}

48

45

49

 

//saves meta options

50

 

function pmpro\_page\_save($post\_id)

51

 

{

 

46

/\*\*

 

47

 \* Saves meta options when a page is saved.

 

48

 \*/

 

49

function pmpro\_page\_save( $post\_id ) {

52

50

    global $wpdb;

53

51

54

 

    if(empty($post\_id))

 

52

    if( empty( $post\_id ) ) {

55

53

        return false;

 

54

    }

56

55

57

 

    if (!empty($\_POST\['pmpro\_noncename'\]) && !wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename(\_\_FILE\_\_) )) {

 

56

    // Post is saving somehow with our meta box not shown.

 

57

    if ( ! isset( $\_POST\['pmpro\_noncename'\] ) ) {

58

58

        return $post\_id;

59

59

    }

60

60

61

 

    // verify if this is an auto save routine. If it is our form has not been submitted, so we dont want

62

 

    // to do anything

63

 

    if ( defined('DOING\_AUTOSAVE') && DOING\_AUTOSAVE )

 

61

    // Verify the nonce.

 

62

    if ( ! wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename( \_\_FILE\_\_ ) ) ) {

64

63

        return $post\_id;

65

 

66

 

    // Check permissions

67

 

    if(!empty($\_POST\['post\_type'\]) && 'page' == $\_POST\['post\_type'\] )

68

 

    {

69

 

        if ( !current\_user\_can( 'edit\_page', $post\_id ) )

70

 

            return $post\_id;

71

 

    }

72

 

    else

73

 

    {

74

 

        if ( !current\_user\_can( 'edit\_post', $post\_id ) )

75

 

            return $post\_id;

76

64

    }

77

65

78

 

    // OK, we're authenticated: we need to find and save the data

79

 

    if(isset($\_POST\['pmpro\_noncename'\]))

80

 

    {

81

 

        if(!empty($\_POST\['page\_levels'\]))

82

 

            $mydata = $\_POST\['page\_levels'\];

83

 

        else

84

 

            $mydata = NULL;

 

66

    // Don't try to update meta fields on AUTOSAVE.

 

67

    if ( defined( 'DOING\_AUTOSAVE' ) && DOING\_AUTOSAVE ) {

 

68

        return $post\_id;

 

69

    }

85

70

86

 

        //remove all memberships for this page

87

 

        $wpdb->query("DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '$post\_id'");

 

71

    // Check permissions.

 

72

    if( ! empty( $\_POST\['post\_type'\] ) && 'page' == $\_POST\['post\_type'\] ) {

 

73

        if ( ! current\_user\_can( 'edit\_page', $post\_id ) ) {

 

74

            return $post\_id;

 

75

        }

 

76

    } else {

 

77

        if ( ! current\_user\_can( 'edit\_post', $post\_id ) ) {

 

78

            return $post\_id;

 

79

        }

 

80

    }

88

81

89

 

        //add new memberships for this page

90

 

        if(is\_array($mydata))

91

 

        {

92

 

            foreach($mydata as $level)

93

 

                $wpdb->query("INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval($level) . "', '" . intval($post\_id) . "')");

 

82

    // OK, we're authenticated. We need to find and save the data.

 

83

    if( ! empty( $\_POST\['page\_levels'\] ) ) {

 

84

        $mydata = $\_POST\['page\_levels'\];

 

85

    } else {

 

86

        $mydata = NULL;

 

87

    }

 

88

 

89

    // Remove all memberships for this page.

 

90

    $wpdb->query( "DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post\_id ) . "'" );

 

91

 

92

    // Add new memberships for this page.

 

93

    if( is\_array( $mydata ) ) {

 

94

        foreach( $mydata as $level ) {

 

95

            $wpdb->query( "INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval( $level ) . "', '" . intval( $post\_id ) . "')" );

94

96

        }

 

97

    }

95

98

96

 

        return $mydata;

97

 

    }

98

 

    else

99

 

        return $post\_id;

 

99

    return $mydata;

100

100

}

101

101

102

 

//wrapper to add meta boxes

103

 

function pmpro\_page\_meta\_wrapper()

104

 

{

105

 

    add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );

106

 

    add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );

 

102

/\*\*

 

103

 \* Wrapper to add meta boxes

 

104

 \*/

 

105

function pmpro\_page\_meta\_wrapper() {

 

106

    add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );

 

107

    add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );

107

108

}

108

 

if (is\_admin())

109

 

{

110

 

    add\_action('admin\_menu', 'pmpro\_page\_meta\_wrapper');

111

 

    add\_action('save\_post', 'pmpro\_page\_save');

 

109

if ( is\_admin() ) {

 

110

    add\_action( 'admin\_menu', 'pmpro\_page\_meta\_wrapper' );

 

111

    add\_action( 'save\_post', 'pmpro\_page\_save' );

112

112

}

113

113

114

 

//show membership level restrictions on category edit

115

 

function pmpro\_taxonomy\_meta($term)

116

 

{

 

114

/\*\*

 

115

 \* Show membership level restrictions on category edit.

 

116

 \*/

 

117

function pmpro\_taxonomy\_meta( $term ) {

117

118

    global $membership\_levels, $post, $wpdb;

118

119

119

120

    $protectedlevels = array();

120

 

    foreach($membership\_levels as $level)

121

 

    {

122

 

        $protectedlevel = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id AND category\_id = $term->term\_id");

123

 

        if(!empty($protectedlevel))

124

 

            $protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . $level->id . '">' . $level->name. '</a>';

 

121

    foreach( $membership\_levels as $level ) {

 

122

        $protectedlevel = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "' AND category\_id = '" . intval( $term->term\_id ) . "'" );

 

123

        if( ! empty( $protectedlevel ) ) {

 

124

            $protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . intval( $level->id ) . '">' . esc\_html( $level->name ) . '</a>';

 

125

        }

125

126

    }

126

 

    if(!empty($protectedlevels))

127

 

    {

128

 

        ?>

129

 

        <tr class="form-field">

130

 

            <th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>

131

 

            <td>

132

 

                <p><strong>

133

 

                    <?php echo implode(', ',$protectedlevels); ?></strong></p>

134

 

                <p class="description"><?php \_e('Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>

135

 

            </td>

136

 

        </tr>

 

127

   

 

128

    if( ! empty( $protectedlevels ) ) {

 

129

    ?>

 

130

    <tr class="form-field">

 

131

        <th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>

 

132

        <td>

 

133

            <p><strong>

 

134

                <?php echo implode(', ',$protectedlevels); ?></strong></p>

 

135

            <p class="description"><?php \_e( 'Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>

 

136

        </td>

 

137

    </tr>

137

138

    <?php

138

139

    }
  • paid-memberships-pro/tags/2.4.3/paid-memberships-pro.php

    r2368140

    r2368689

4

4

 \* Plugin URI: https://www.paidmembershipspro.com

5

5

 \* Description: The most complete member management and membership subscriptions plugin for WordPress.

6

 

 \* Version: 2.4.2

 

6

 \* Version: 2.4.3

7

7

 \* Author: Stranger Studios

8

8

 \* Author URI: https://www.strangerstudios.com

…

…

 

17

17

18

18

// version constant

19

 

define( 'PMPRO\_VERSION', '2.4.2' );

 

19

define( 'PMPRO\_VERSION', '2.4.3' );

20

20

define( 'PMPRO\_USER\_AGENT', 'Paid Memberships Pro v' . PMPRO\_VERSION . '; ' . site\_url() );

21

21

define( 'PMPRO\_MIN\_PHP\_VERSION', '5.6' );
  • paid-memberships-pro/tags/2.4.3/readme.txt

    r2368140

    r2368689

4

4

Requires at least: 4

5

5

Tested up to: 5.5

6

 

Stable tag: 2.4.2

 

6

Stable tag: 2.4.3

7

7

8

8

Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.

…

…

 

154

154

155

155

\== Changelog ==

 

156

\= 2.4.3 - 2020-08-25

 

157

\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)

 

158

\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.

 

159

\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.

 

160

156

161

\= 2.4.2 - 2020-08-24

157

162

\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
  • paid-memberships-pro/trunk/CHANGELOG.txt

    r2368140

    r2368689

1

1

\== Changelog ==

 

2

\= 2.4.3 - 2020-08-25

 

3

\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)

 

4

\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.

 

5

\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.

 

6

2

7

\= 2.4.2 - 2020-08-24

3

8

\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
  • paid-memberships-pro/trunk/includes/metaboxes.php

    r2098264

    r2368689

1

1

<?php

2

 

/\*

3

 

    Require Membership Meta Box

4

 

\*/

5

 

function pmpro\_page\_meta()

6

 

{

 

2

/\*\*

 

3

 \* Require Membership Meta Box

 

4

 \*/

 

5

function pmpro\_page\_meta() {

7

6

    global $post, $wpdb;

8

 

    $membership\_levels = pmpro\_getAllLevels(true, true);

9

 

    $page\_levels = $wpdb->get\_col("SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '{$post->ID}'");

 

7

    $membership\_levels = pmpro\_getAllLevels( true, true );

 

8

    $page\_levels = $wpdb->get\_col( "SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post->ID ) . "'" );

10

9

?>

11

10

    <ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">

12

 

    <input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) )?>" />

 

11

    <input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo esc\_attr( wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) ) )?>" />

13

12

    <?php

14

13

        $in\_member\_cat = false;

15

 

        foreach($membership\_levels as $level)

16

 

        {

17

 

    ?>

18

 

        <li id="membership-level-<?php echo $level->id?>">

 

14

        foreach( $membership\_levels as $level ) {

 

15

        ?>

 

16

        <li id="membership-level-<?php echo esc\_attr( $level->id ); ?>">

19

17

            <label class="selectit">

20

 

                <input id="in-membership-level-<?php echo $level->id?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo $level->id?>" />

 

18

                <input id="in-membership-level-<?php echo esc\_attr( $level->id ); ?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo esc\_attr( $level->id ) ;?>" />

21

19

                <?php

22

 

                    echo $level->name;

 

20

                    echo esc\_html( $level->name );

23

21

                    //Check which categories are protected for this level

24

 

                    $protectedcategories = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id");

 

22

                    $protectedcategories = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "'");

25

23

                    //See if this post is in any of the level's protected categories

26

 

                    if(in\_category($protectedcategories, $post->id))

27

 

                    {

 

24

                    if( in\_category( $protectedcategories, $post->id ) ) {

28

25

                        $in\_member\_cat = true;

29

26

                        echo ' \*';

…

…

 

32

29

            </label>

33

30

        </li>

34

 

    <?php

 

31

        <?php

35

32

        }

36

33

    ?>

37

34

    </ul>

38

35

    <?php

39

 

        if('post' == get\_post\_type($post) && $in\_member\_cat) { ?>

 

36

        if( 'post' == get\_post\_type( $post ) && $in\_member\_cat ) { ?>

40

37

        <p class="pmpro\_meta\_notice">\* <?php \_e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>

41

38

    <?php

42

39

        }

43

40

44

 

        do\_action('pmpro\_after\_require\_membership\_metabox', $post);

 

41

        do\_action( 'pmpro\_after\_require\_membership\_metabox', $post );

45

42

    ?>

46

43

<?php

47

44

}

48

45

49

 

//saves meta options

50

 

function pmpro\_page\_save($post\_id)

51

 

{

 

46

/\*\*

 

47

 \* Saves meta options when a page is saved.

 

48

 \*/

 

49

function pmpro\_page\_save( $post\_id ) {

52

50

    global $wpdb;

53

51

54

 

    if(empty($post\_id))

 

52

    if( empty( $post\_id ) ) {

55

53

        return false;

 

54

    }

56

55

57

 

    if (!empty($\_POST\['pmpro\_noncename'\]) && !wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename(\_\_FILE\_\_) )) {

 

56

    // Post is saving somehow with our meta box not shown.

 

57

    if ( ! isset( $\_POST\['pmpro\_noncename'\] ) ) {

58

58

        return $post\_id;

59

59

    }

60

60

61

 

    // verify if this is an auto save routine. If it is our form has not been submitted, so we dont want

62

 

    // to do anything

63

 

    if ( defined('DOING\_AUTOSAVE') && DOING\_AUTOSAVE )

 

61

    // Verify the nonce.

 

62

    if ( ! wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename( \_\_FILE\_\_ ) ) ) {

64

63

        return $post\_id;

65

 

66

 

    // Check permissions

67

 

    if(!empty($\_POST\['post\_type'\]) && 'page' == $\_POST\['post\_type'\] )

68

 

    {

69

 

        if ( !current\_user\_can( 'edit\_page', $post\_id ) )

70

 

            return $post\_id;

71

 

    }

72

 

    else

73

 

    {

74

 

        if ( !current\_user\_can( 'edit\_post', $post\_id ) )

75

 

            return $post\_id;

76

64

    }

77

65

78

 

    // OK, we're authenticated: we need to find and save the data

79

 

    if(isset($\_POST\['pmpro\_noncename'\]))

80

 

    {

81

 

        if(!empty($\_POST\['page\_levels'\]))

82

 

            $mydata = $\_POST\['page\_levels'\];

83

 

        else

84

 

            $mydata = NULL;

 

66

    // Don't try to update meta fields on AUTOSAVE.

 

67

    if ( defined( 'DOING\_AUTOSAVE' ) && DOING\_AUTOSAVE ) {

 

68

        return $post\_id;

 

69

    }

85

70

86

 

        //remove all memberships for this page

87

 

        $wpdb->query("DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '$post\_id'");

 

71

    // Check permissions.

 

72

    if( ! empty( $\_POST\['post\_type'\] ) && 'page' == $\_POST\['post\_type'\] ) {

 

73

        if ( ! current\_user\_can( 'edit\_page', $post\_id ) ) {

 

74

            return $post\_id;

 

75

        }

 

76

    } else {

 

77

        if ( ! current\_user\_can( 'edit\_post', $post\_id ) ) {

 

78

            return $post\_id;

 

79

        }

 

80

    }

88

81

89

 

        //add new memberships for this page

90

 

        if(is\_array($mydata))

91

 

        {

92

 

            foreach($mydata as $level)

93

 

                $wpdb->query("INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval($level) . "', '" . intval($post\_id) . "')");

 

82

    // OK, we're authenticated. We need to find and save the data.

 

83

    if( ! empty( $\_POST\['page\_levels'\] ) ) {

 

84

        $mydata = $\_POST\['page\_levels'\];

 

85

    } else {

 

86

        $mydata = NULL;

 

87

    }

 

88

 

89

    // Remove all memberships for this page.

 

90

    $wpdb->query( "DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post\_id ) . "'" );

 

91

 

92

    // Add new memberships for this page.

 

93

    if( is\_array( $mydata ) ) {

 

94

        foreach( $mydata as $level ) {

 

95

            $wpdb->query( "INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval( $level ) . "', '" . intval( $post\_id ) . "')" );

94

96

        }

 

97

    }

95

98

96

 

        return $mydata;

97

 

    }

98

 

    else

99

 

        return $post\_id;

 

99

    return $mydata;

100

100

}

101

101

102

 

//wrapper to add meta boxes

103

 

function pmpro\_page\_meta\_wrapper()

104

 

{

105

 

    add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );

106

 

    add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );

 

102

/\*\*

 

103

 \* Wrapper to add meta boxes

 

104

 \*/

 

105

function pmpro\_page\_meta\_wrapper() {

 

106

    add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );

 

107

    add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );

107

108

}

108

 

if (is\_admin())

109

 

{

110

 

    add\_action('admin\_menu', 'pmpro\_page\_meta\_wrapper');

111

 

    add\_action('save\_post', 'pmpro\_page\_save');

 

109

if ( is\_admin() ) {

 

110

    add\_action( 'admin\_menu', 'pmpro\_page\_meta\_wrapper' );

 

111

    add\_action( 'save\_post', 'pmpro\_page\_save' );

112

112

}

113

113

114

 

//show membership level restrictions on category edit

115

 

function pmpro\_taxonomy\_meta($term)

116

 

{

 

114

/\*\*

 

115

 \* Show membership level restrictions on category edit.

 

116

 \*/

 

117

function pmpro\_taxonomy\_meta( $term ) {

117

118

    global $membership\_levels, $post, $wpdb;

118

119

119

120

    $protectedlevels = array();

120

 

    foreach($membership\_levels as $level)

121

 

    {

122

 

        $protectedlevel = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id AND category\_id = $term->term\_id");

123

 

        if(!empty($protectedlevel))

124

 

            $protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . $level->id . '">' . $level->name. '</a>';

 

121

    foreach( $membership\_levels as $level ) {

 

122

        $protectedlevel = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "' AND category\_id = '" . intval( $term->term\_id ) . "'" );

 

123

        if( ! empty( $protectedlevel ) ) {

 

124

            $protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . intval( $level->id ) . '">' . esc\_html( $level->name ) . '</a>';

 

125

        }

125

126

    }

126

 

    if(!empty($protectedlevels))

127

 

    {

128

 

        ?>

129

 

        <tr class="form-field">

130

 

            <th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>

131

 

            <td>

132

 

                <p><strong>

133

 

                    <?php echo implode(', ',$protectedlevels); ?></strong></p>

134

 

                <p class="description"><?php \_e('Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>

135

 

            </td>

136

 

        </tr>

 

127

   

 

128

    if( ! empty( $protectedlevels ) ) {

 

129

    ?>

 

130

    <tr class="form-field">

 

131

        <th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>

 

132

        <td>

 

133

            <p><strong>

 

134

                <?php echo implode(', ',$protectedlevels); ?></strong></p>

 

135

            <p class="description"><?php \_e( 'Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>

 

136

        </td>

 

137

    </tr>

137

138

    <?php

138

139

    }
  • paid-memberships-pro/trunk/paid-memberships-pro.php

    r2368140

    r2368689

4

4

 \* Plugin URI: https://www.paidmembershipspro.com

5

5

 \* Description: The most complete member management and membership subscriptions plugin for WordPress.

6

 

 \* Version: 2.4.2

 

6

 \* Version: 2.4.3

7

7

 \* Author: Stranger Studios

8

8

 \* Author URI: https://www.strangerstudios.com

…

…

 

17

17

18

18

// version constant

19

 

define( 'PMPRO\_VERSION', '2.4.2' );

 

19

define( 'PMPRO\_VERSION', '2.4.3' );

20

20

define( 'PMPRO\_USER\_AGENT', 'Paid Memberships Pro v' . PMPRO\_VERSION . '; ' . site\_url() );

21

21

define( 'PMPRO\_MIN\_PHP\_VERSION', '5.6' );
  • paid-memberships-pro/trunk/readme.txt

    r2368140

    r2368689

4

4

Requires at least: 4

5

5

Tested up to: 5.5

6

 

Stable tag: 2.4.2

 

6

Stable tag: 2.4.3

7

7

8

8

Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.

…

…

 

154

154

155

155

\== Changelog ==

 

156

\= 2.4.3 - 2020-08-25

 

157

\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)

 

158

\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.

 

159

\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.

 

160

156

161

\= 2.4.2 - 2020-08-24

157

162

\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.

Note: See TracChangeset for help on using the changeset viewer.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907