Headline
CVE-2023-0162: Diff [2574013:2844012] for cpo-companion/trunk – WordPress Plugin Repository
The CPO Companion plugin for WordPress is vulnerable to Stored Cross-Site Scripting via several of its content type settings parameters in versions up to, and including, 1.0.4 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
cpo-companion/trunk/cpo-companion.php
r2574013
r2844012
3
3
Plugin Name: CPO Companion
4
4
Description: Creates Post Types, Shortcodes and Widgets in order to create a powerful business website.
5
Author: WPChill
6
Version: 1.0.4
7
Author URI: https://wpchill.com
5
Author: MachoThemes
6
Version: 1.1.0
7
Author URI: https://www.machothemes.com
8
8
\*/
9
9
cpo-companion/trunk/includes/class-cpo-settings-page.php
r2574013
r2844012
218
218
public function settings\_page() {
219
219
220
$tab = isset( $\_GET\['tab'\] ) ? $\_GET\['tab'\] : 'settings';
220
$tab = isset( $\_GET\['tab'\] ) ? sanitize\_text\_field( wp\_unslash( $\_GET\['tab'\] ) ) : 'settings';
221
221
if ( 'shortcodes' != $tab ) {
222
222
$tab = 'settings';
…
…
224
224
225
225
echo '<h2 class="nav-tab-wrapper wp-clearfix">';
226
echo '<a class="nav-tab ' . ( 'settings' == $tab ? 'nav-tab-active' : '' ) . '" href="' . admin\_url( 'options-general.php?page=cpo\_companion\_settings&tab=settings' ) . '">' . esc\_html\_\_( 'Content Types', 'cpo-companion' ) . '</a>';
227
echo '<a class="nav-tab ' . ( 'shortcodes' == $tab ? 'nav-tab-active' : '' ) . '" href="' . admin\_url( 'options-general.php?page=cpo\_companion\_settings&tab=shortcodes' ) . '">' . esc\_html\_\_( 'Shortcodes', 'cpo-companion' ) . '</a>';
226
echo '<a class="nav-tab ' . ( 'settings' == $tab ? 'nav-tab-active' : '' ) . '" href="' . esc\_url( admin\_url( 'options-general.php?page=cpo\_companion\_settings&tab=settings' ) ) . '">' . esc\_html\_\_( 'Content Types', 'cpo-companion' ) . '</a>';
227
echo '<a class="nav-tab ' . ( 'shortcodes' == $tab ? 'nav-tab-active' : '' ) . '" href="' . esc\_url( admin\_url( 'options-general.php?page=cpo\_companion\_settings&tab=shortcodes' ) ) . '">' . esc\_html\_\_( 'Shortcodes', 'cpo-companion' ) . '</a>';
228
228
echo '</h2>';
229
229
…
…
282
282
foreach ( $this->settings\_sections as $setting\_id => $setting\_data ) {
283
283
if ( $args\['id'\] == $setting\_id ) {
284
echo '<p>' . $setting\_data\['description'\] . '</p>';
284
echo '<p>' . wp\_kses\_post( $setting\_data\['description'\] ) . '</p>';
285
285
}
286
286
}
…
…
300
300
switch ( $args\['type'\] ) {
301
301
case 'text':
302
echo '<input name="' . $args\['setting'\] . '\[' . $args\['id'\] . '\]" type="text" id="' . $args\['id'\] . '" value="' . $args\['value'\] . '" placeholder="' . $args\['placeholder'\] . '" class="' . $args\['class'\] . '"/>';
302
echo '<input name="' . esc\_attr( $args\['setting'\] ) . '\[' . esc\_attr( $args\['id'\] ) . '\]" type="text" id="' . esc\_attr( $args\['id'\] ) . '" value="' . esc\_attr( $args\['value'\] ) . '" placeholder="' . esc\_attr( $args\['placeholder'\] ) . '" class="' . esc\_attr( $args\['class'\] ) . '"/>';
303
303
if ( isset( $args\['description'\] ) && '' != $args\['description'\] ) {
304
echo '<p class="description">' . $args\['description'\] . '</p>';
304
echo '<p class="description">' . wp\_kses\_post( $args\['description'\] ) . '</p>';
305
305
}
306
306
break;
307
307
308
308
case 'checkbox':
309
echo '<label for="' . $args\['id'\] . '"><input name="' . $args\['setting'\] . '\[' . $args\['id'\] . '\]" type="checkbox" value="1" id="' . $args\['id'\] . '" ' . checked( 1, $args\['value'\], false ) . '" placeholder="' . $args\['placeholder'\] . '" class="' . $args\['class'\] . '"/> ' . $args\['description'\] . '</label>';
309
echo '<label for="' . esc\_attr( $args\['id'\] ) . '"><input name="' . esc\_attr( $args\['setting'\] ) . '\[' . esc\_attr( $args\['id'\] ) . '\]" type="checkbox" value="1" id="' . esc\_attr( $args\['id'\] ) . '" ' . checked( 1, $args\['value'\], false ) . '" placeholder="' . esc\_attr( $args\['placeholder'\] ) . '" class="' . esc\_attr( $args\['class'\] ) . '"/> ' . wp\_kses\_post( $args\['description'\] ) . '</label>';
310
310
if ( isset( $args\['description'\] ) && '' != $args\['description'\] ) {
311
echo '<p class="description">' . $args\['description'\] . '</p>';
311
echo '<p class="description">' . wp\_kses\_post( $args\['description'\] ) . '</p>';
312
312
}
313
313
break;
cpo-companion/trunk/includes/import/class-cpo-companion-import.php
r2574013
r2844012
146
146
147
147
$create\_users = $this->allow\_create\_users();
148
149
foreach ( (array) $\_POST\['imported\_authors'\] as $i => $old\_login ) {
148
$imported\_authors = array\_map( 'sanitize\_text\_field', wp\_unslash( $\_POST\['imported\_authors'\] ) );
149
foreach ( $imported\_authors as $i => $old\_login ) {
150
150
// Multisite adds strtolower to sanitize\_user. Need to sanitize here to stop breakage in process\_posts.
151
151
$santized\_old\_login = sanitize\_user( $old\_login, true );
…
…
162
162
} elseif ( $create\_users ) {
163
163
if ( ! empty( $\_POST\['user\_new'\]\[ $i \] ) ) {
164
$user\_id = wp\_create\_user( $\_POST\['user\_new'\]\[ $i \], wp\_generate\_password() );
164
$user\_new = sanitize\_text\_field( wp\_unslash( $\_POST\['user\_new'\]\[ $i \] ) );
165
$user\_id = wp\_create\_user( $user\_new, wp\_generate\_password() );
165
166
} elseif ( '1.0' != $this->version ) {
166
167
$user\_data = array(
cpo-companion/trunk/includes/shortcodes/shortcode-register.php
r2574013
r2844012
37
37
//If form has been sent, there must be an error
38
38
if ( isset( $\_POST\['ctsc-register-submit'\] ) ) {
39
$error\_message = isset( $\_POST\['ctsc-register-error'\] ) ? esc\_html( $\_POST\['ctsc-register-error'\] ) : false;
39
$error\_message = isset( $\_POST\['ctsc-register-error'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-error'\] ) ) : false;
40
40
if ( $error\_message ) {
41
41
wp\_enqueue\_style( 'cpo-companion-fontawesome' );
…
…
49
49
50
50
//Username
51
$field\_username = isset( $\_POST\['ctsc-register-username'\] ) ? $\_POST\['ctsc-register-username'\] : '';
51
$field\_username = isset( $\_POST\['ctsc-register-username'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-username'\] ) ) : '';
52
52
$output .= '<div class="ctsc-register-field">';
53
53
$output .= '<input type="text" class="ctsc-register-username" name="ctsc-register-username" value="' . esc\_attr( $field\_username ) . '" placeholder="' . esc\_attr( $attributes\['username'\] ) . '" required>';
…
…
55
55
56
56
//Email
57
$field\_email = isset( $\_POST\['ctsc-register-email'\] ) ? $\_POST\['ctsc-register-email'\] : '';
57
$field\_email = isset( $\_POST\['ctsc-register-email'\] ) ? sanitize\_email( wp\_unslash( $\_POST\['ctsc-register-email'\] ) ) : '';
58
58
$output .= '<div class="ctsc-register-field">';
59
59
$output .= '<input type="text" class="ctsc-register-email" name="ctsc-register-email" value="' . esc\_attr( $field\_email ) . '" placeholder="' . esc\_attr( $attributes\['email'\] ) . '" required>';
…
…
62
62
//First Name
63
63
if ( '' != $firstname ) {
64
$field\_firstname = isset( $\_POST\['ctsc-register-firstname'\] ) ? $\_POST\['ctsc-register-firstname'\] : '';
64
$field\_firstname = isset( $\_POST\['ctsc-register-firstname'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-firstname'\] ) ) : '';
65
65
$output .= '<div class="ctsc-register-field">';
66
66
$output .= '<input type="text" class="ctsc-register-username" name="ctsc-register-firstname" value="' . esc\_attr( $field\_firstname ) . '" placeholder="' . esc\_attr( $attributes\['firstname'\] ) . '" required>';
…
…
69
69
70
70
//Password
71
$field\_password = isset( $\_POST\['ctsc-register-password'\] ) ? $\_POST\['ctsc-register-password'\] : '';
71
$field\_password = isset( $\_POST\['ctsc-register-password'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-password'\] ) ) : '';
72
72
$output .= '<div class="ctsc-register-field">';
73
73
$output .= '<input type="password" class="ctsc-register-password" name="ctsc-register-password" value="' . esc\_attr( $field\_password ) . '" placeholder="' . esc\_attr( $attributes\['password'\] ) . '" required>';
…
…
101
101
if ( isset( $\_POST\['ctsc-register-submit'\] ) ) {
102
102
//Validate all fields
103
$field\_username = isset( $\_POST\['ctsc-register-username'\] ) ? esc\_attr( $\_POST\['ctsc-register-username'\] ) : false;
104
$field\_email = isset( $\_POST\['ctsc-register-email'\] ) ? esc\_attr( $\_POST\['ctsc-register-email'\] ) : false;
105
$field\_firstname = isset( $\_POST\['ctsc-register-firstname'\] ) ? esc\_attr( $\_POST\['ctsc-register-firstname'\] ) : false;
106
$field\_password = isset( $\_POST\['ctsc-register-password'\] ) ? esc\_attr( $\_POST\['ctsc-register-password'\] ) : false;
107
$field\_captcha = isset( $\_POST\['ctsc-register-check'\] ) ? esc\_attr( $\_POST\['ctsc-register-check'\] ) : false;
108
$field\_redirect = isset( $\_POST\['ctsc-register-redirect'\] ) ? esc\_url( $\_POST\['ctsc-register-redirect'\] ) : false;
103
$field\_username = isset( $\_POST\['ctsc-register-username'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-username'\] ) ): false;
104
$field\_email = isset( $\_POST\['ctsc-register-email'\] ) ? sanitize\_email( wp\_unslash( $\_POST\['ctsc-register-email'\] ) ) : false;
105
$field\_firstname = isset( $\_POST\['ctsc-register-firstname'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-firstname'\] ) ) : false;
106
$field\_password = isset( $\_POST\['ctsc-register-password'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-password'\] ) ) : false;
107
$field\_captcha = isset( $\_POST\['ctsc-register-check'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-check'\] ) ) : false;
108
$field\_redirect = isset( $\_POST\['ctsc-register-redirect'\] ) ? sanitize\_text\_field( wp\_unslash( $\_POST\['ctsc-register-redirect'\] ) ) : false;
109
109
110
110
//Validate Required Fields
cpo-companion/trunk/includes/shortcodes/shortcode-testimonial.php
r2574013
r2844012
19
19
$element\_class = ' ' . $attributes\['class'\];
20
20
$element\_style = ' ctsc-testimonial-' . $attributes\['style'\];
21
$element\_id = '' != $attributes\['id'\] ? ' id="' . $attributes\['id'\] . '"' : '';
22
21
$content = trim( $content );
23
22
…
…
37
36
}
38
37
39
$output = '<div class="ctsc-testimonial' . esc\_attr( $element\_class ) . '"' . $element\_id . '>';
38
$output = '<div class="ctsc-testimonial' . esc\_attr( $element\_class ) . '"' . ( '' != esc\_attr( $attributes\['id'\] ) ? ' id="' . esc\_attr( $attributes\['id'\] ) . '"' : '' ) . '>';
40
39
$output .= '<div class="ctsc-testimonial-content">';
41
40
$output .= wp\_kses\_post( $content );
cpo-companion/trunk/includes/widgets/class-cpo-widget-advert.php
r2574013
r2844012
15
15
$title = apply\_filters( 'widget\_title', $instance\['title'\] );
16
16
17
echo $args\['before\_widget'\];
17
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
18
18
if ( '' != $title ) {
19
echo $args\['before\_title'\] . $title . $args\['after\_title'\];
19
echo $args\['before\_title'\] . $title . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
20
20
} ?>
21
<div class="ctwg-advert" id="<?php echo $args\['widget\_id'\]; ?>">
21
<div class="ctwg-advert" id="<?php echo esc\_attr( $args\['widget\_id'\] ); ?>">
22
22
<?php if ( '' == $instance\['ad\_code'\] ) : ?>
23
23
<a href="<?php echo esc\_url( $instance\['link\_url'\] ); ?>">
…
…
25
25
</a>
26
26
<?php else : ?>
27
<?php echo htmlspecialchars\_decode( $instance\['ad\_code'\] ); ?>
27
<?php echo htmlspecialchars\_decode( $instance\['ad\_code'\] ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
28
28
<?php endif; ?>
29
29
</div>
30
30
<?php
31
echo $args\['after\_widget'\];
31
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
32
32
}
33
33
…
…
67
67
<input class="widefat" id="<?php echo esc\_attr( $this->get\_field\_id( 'link\_url' ) ); ?>" name="<?php echo esc\_attr( $this->get\_field\_name( 'link\_url' ) ); ?>" type="text" value="<?php echo esc\_attr( $link\_url ); ?>" />
68
68
</p>
69
<p><b>- <?php \_e( 'or', 'cpo-companion' ); ?> -</b></p>
69
<p><b>- <?php esc\_html\_e( 'or', 'cpo-companion' ); ?> -</b></p>
70
70
<p>
71
71
<label for="<?php echo esc\_attr( $this->get\_field\_id( 'ad\_code' ) ); ?>"><?php esc\_html\_e( 'Advertising Code', 'cpo-companion' ); ?></label><br/>
72
72
<textarea class="widefat" id="<?php echo esc\_attr( $this->get\_field\_id( 'ad\_code' ) ); ?>" name="<?php echo esc\_attr( $this->get\_field\_name( 'ad\_code' ) ); ?>">
73
<?php echo htmlspecialchars\_decode( $ad\_code ); ?>
73
<?php echo htmlspecialchars\_decode( $ad\_code ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
74
74
</textarea>
75
75
</p>
cpo-companion/trunk/includes/widgets/class-cpo-widget-author.php
r2574013
r2844012
34
34
$output .= '</div>';
35
35
36
echo $args\['before\_widget'\];
36
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
37
37
if ( '' != $title ) {
38
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
38
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
39
39
}
40
echo $output;
41
echo $args\['after\_widget'\];
40
echo $output; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
41
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
42
42
}
43
43
cpo-companion/trunk/includes/widgets/class-cpo-widget-flickr.php
r2574013
r2844012
37
37
$photos = array\_slice( $photos, 0, $number );
38
38
39
echo $args\['before\_widget'\];
39
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
40
40
if ( '' != $title ) {
41
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
41
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
42
42
}
43
43
?>
…
…
51
51
</div>
52
52
<?php
53
echo $args\['after\_widget'\];
53
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
54
54
55
55
set\_transient( 'cpo\_widget\_flickr\_' . $this->id, $data, 12 \* HOUR\_IN\_SECONDS );
cpo-companion/trunk/includes/widgets/class-cpo-widget-instagram.php
r2574013
r2844012
35
35
}
36
36
37
echo $args\['before\_widget'\];
37
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
38
38
if ( '' != $title ) {
39
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
39
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
40
40
}
41
41
…
…
50
50
</div>
51
51
<?php
52
echo $args\['after\_widget'\];
52
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
53
53
54
54
set\_transient( 'cpo\_widget\_instagram\_' . $this->id, $data, 12 \* HOUR\_IN\_SECONDS );
cpo-companion/trunk/includes/widgets/class-cpo-widget-recent-posts.php
r2574013
r2844012
22
22
23
23
if ( isset( $cache\[ $args\['widget\_id'\] \] ) ) {
24
echo $cache\[ $args\['widget\_id'\] \];
24
echo $cache\[ $args\['widget\_id'\] \]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
25
25
return;
26
26
}
…
…
48
48
);
49
49
if ( $recent\_posts->have\_posts() ) :
50
echo $args\['before\_widget'\];
50
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
51
51
if ( '' != $title ) {
52
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
52
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
53
53
} ?>
54
54
…
…
79
79
</div>
80
80
<?php
81
echo $args\['after\_widget'\];
81
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
82
82
wp\_reset\_postdata();
83
83
endif;
cpo-companion/trunk/includes/widgets/class-cpo-widget-social.php
r2574013
r2844012
26
26
$page\_dribbble = esc\_attr( $instance\['page\_dribbble'\] );
27
27
28
echo $args\['before\_widget'\];
28
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
29
29
if ( '' != $title ) {
30
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
30
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
31
31
} ?>
32
32
<div class="ctwg-social" >
…
…
88
88
</div>
89
89
<?php
90
echo $args\['after\_widget'\];
90
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
91
91
}
92
92
cpo-companion/trunk/includes/widgets/class-cpo-widget-tweets.php
r2574013
r2844012
95
95
}
96
96
97
echo $args\['before\_widget'\];
97
echo $args\['before\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
98
98
if ( '' != $title ) {
99
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\];
99
echo $args\['before\_title'\] . esc\_html( $title ) . $args\['after\_title'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
100
100
}
101
101
if ( '' == $output ) {
102
102
$output .= 'Impossible to retrieve tweets. Try again later.';
103
103
}
104
echo $output;
105
echo $args\['after\_widget'\];
104
echo $output; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
105
echo $args\['after\_widget'\]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
106
106
}
107
107
…
…
144
144
<input id="<?php echo esc\_attr( $this->get\_field\_id( 'number' ) ); ?>" name="<?php echo esc\_attr( $this->get\_field\_name( 'number' ) ); ?>" type="text" value="<?php echo esc\_attr( $instance\['number'\] ); ?>" size="3" />
145
145
</p>
146
<p><b><?php \_e( 'API Settings', 'cpo-companion' ); ?></b></p>
146
<p><b><?php esc\_html\_e( 'API Settings', 'cpo-companion' ); ?></b></p>
147
147
<p>
148
148
<label for="<?php echo esc\_attr( $this->get\_field\_id( 'consumer\_key' ) ); ?>"><?php esc\_html\_e( 'Consumer Key', 'cpo-companion' ); ?></label><br/>
cpo-companion/trunk/readme.txt
r2574013
r2844012
1
1
\=== CPO Companion ===
2
Contributors: wpchill
2
Contributors: machothemes
3
3
Tags: cpo companion, shortcodes, author widget, instagram widget, flickr widget, twitter widget, custom post types, clients, sliders, team members, services, portfolios
4
Requires at least: 5.2
5
Tested up to: 5.8
6
Stable tag: 1.0.4
4
Requires at least: 3.8
5
Tested up to: 6.1
6
Stable tag: 1.1.0
7
7
License: GPLv3 or later
8
8
License URI: https://www.gnu.org/licenses/gpl-3.0.html
…
…
80
80
\*\*Author Badge\*\* - Display the profile of a specific user, showing the name, image, and profile description.
81
81
82
\> This plugin is maintained and supported by Macho Themes.
83
\> Check out some of the other <a href="//machothemes.com/plugins/" rel="nofollow">WordPress plugins</a> we've developed.
84
\> Check out some of the other <a href="//machothemes.com/themes/free/" rel="nofollow">free WordPress themes</a> we've developed.
82
85
83
86
\== Installation ==
…
…
114
117
\== Changelog ==
115
118
119
\= 1.1.0 =
120
\* Fixed vulnerability report, sanitizations and escapes.
121
116
122
\= 1.0.4 =
117
123
\* Added option for changing Team Member URL