Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/broadstreet/Broadstreet/Ajax.php
+++ b/broadstreet/Broadstreet/Ajax.php
@@ -19,6 +19,14 @@
*/
public static function saveSettings()
{
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+
// Sanitize the API key before storing it
$api_key = sanitize_text_field($_POST['api_key']);
Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $api_key);
@@ -64,6 +72,16 @@
*/
public static function saveZoneSettings()
{
+ // Verify nonce (passed as URL parameter) and check user permissions
+ // Note: Using $_GET since nonce is in URL, not in php://input JSON body
+ if (!isset($_GET['nonce']) || !wp_verify_nonce($_GET['nonce'], 'broadstreet_ajax_nonce')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Security check failed')));
+ }
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
$settings = json_decode(file_get_contents("php://input"));
if($settings)
@@ -81,25 +99,60 @@
public static function createAdvertiser()
{
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+
$api_key = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_API_KEY);
$network_id = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_NETWORK_ID);
$api = Broadstreet_Utility::getBroadstreetClient();
- $advertiser = $api->createAdvertiser($network_id, stripslashes($_POST['name']));
+ // Sanitize advertiser name to prevent XSS
+ $name = sanitize_text_field(stripslashes($_POST['name']));
+ $advertiser = $api->createAdvertiser($network_id, $name);
die(json_encode(array('success' => true, 'advertiser' => $advertiser)));
}
public static function getSponsorPostMeta() {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('edit_posts')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
$post_id = isset($_GET['post_id']) ? intval($_GET['post_id']) : 0;
+
+ // Verify user has permission to edit this post (fixes IDOR vulnerability)
+ if (!current_user_can('edit_post', $post_id)) {
+ die(json_encode(array('success' => false, 'error' => 'Permission denied')));
+ }
+
+ // Verify nonce and referer (fixes CSRF vulnerability)
+ check_ajax_referer('broadstreet_sponsor_nonce', '_wpnonce');
+
die(json_encode(array('success' => true, 'meta' => Broadstreet_Utility::getAllPostMeta($post_id))));
}
public static function importFacebook()
{
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('edit_posts')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
+
try
{
- $profile = Broadstreet_Utility::importBusiness($_POST['id'], $_POST['post_id']);
+ $profile = Broadstreet_Utility::importBusiness(sanitize_text_field($_POST['id']), $post_id);
die(json_encode(array('success' => (bool)$profile, 'profile' => $profile)));
}
catch(Broadstreet_ServerException $ex)
@@ -110,12 +163,20 @@
public static function register()
{
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+
$api = Broadstreet_Utility::getBroadstreetClient(true);
try
{
# Register the user by email address
- $resp = $api->register($_POST['email']);
+ $resp = $api->register(sanitize_email($_POST['email']));
Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $resp->access_token);
# Create a network for the new user
--- a/broadstreet/Broadstreet/Config.php
+++ b/broadstreet/Broadstreet/Config.php
@@ -140,4 +140,4 @@
}
}
-define('BROADSTREET_VERSION', '1.52.2');
+define('BROADSTREET_VERSION', '1.53.2');
--- a/broadstreet/Broadstreet/Core.php
+++ b/broadstreet/Broadstreet/Core.php
@@ -669,6 +669,13 @@
//if(!$info || !$info->cc_on_file)
// echo '<div class="updated"><p>You're <strong>almost ready</strong> to start using Broadstreet! Check the <a href="admin.php?page=Broadstreet">plugin page</a> to take care of the last steps. When that's done, this message will clear shortly after.</p></div>';
+
+ // Check for video security warning
+ $security_warning = get_transient('broadstreet_video_security_warning_' . get_current_user_id());
+ if ($security_warning) {
+ echo '<div class="notice notice-error is-dismissible"><p><strong>Broadstreet Security Notice:</strong> Potentially malicious content was detected and removed from the video embed field. JavaScript protocols, event handlers, and script tags are not allowed for security reasons.</p></div>';
+ delete_transient('broadstreet_video_security_warning_' . get_current_user_id());
+ }
}
}
@@ -688,6 +695,11 @@
wp_enqueue_script('angular-js', Broadstreet_Utility::getJSBaseURL().'angular.min.js?v='. BROADSTREET_VERSION);
wp_enqueue_script('isteven-multi-js', Broadstreet_Utility::getJSBaseURL().'isteven-multi-select.js');
wp_enqueue_style ('isteven-multi-css', Broadstreet_Utility::getCSSBaseURL() . 'isteven-multi-select.css');
+
+ // Pass nonce to JavaScript for AJAX security
+ wp_localize_script('Broadstreet-main', 'broadstreetAjax', [
+ 'nonce' => wp_create_nonce('broadstreet_ajax_nonce')
+ ]);
}
# Only register on the post editing page
@@ -697,6 +709,11 @@
wp_enqueue_style ('Broadstreet-vendorcss-time', Broadstreet_Utility::getVendorBaseURL() . 'timepicker/css/timePicker.css');
wp_enqueue_script('Broadstreet-main' , Broadstreet_Utility::getJSBaseURL().'broadstreet.js?v='. BROADSTREET_VERSION);
wp_enqueue_script('Broadstreet-vendorjs-time' , Broadstreet_Utility::getVendorBaseURL().'timepicker/js/jquery.timePicker.min.js');
+
+ // Pass nonce to JavaScript for AJAX security
+ wp_localize_script('Broadstreet-main', 'broadstreetAjax', [
+ 'nonce' => wp_create_nonce('broadstreet_ajax_nonce')
+ ]);
}
}
@@ -812,11 +829,29 @@
}
public function adminMenuBusinessCallback() {
-
- if (isset($_POST['featured_business_image'])) {
- $featured_image = Broadstreet_Utility::featuredBusinessImage($_POST['featured_business_image']);
+ // Handle POSTed settings securely
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Require capability
+ if (!current_user_can('manage_options')) {
+ wp_die('Permission denied');
+ }
+
+ // Verify nonce for the businesses settings form
+ check_admin_referer('broadstreet_business_nonce');
+
+ // Sanitize and persist the featured image setting
+ if (isset($_POST['featured_business_image'])) {
+ $featured_image_value = sanitize_text_field($_POST['featured_business_image']);
+ $featured_image = Broadstreet_Utility::featuredBusinessImage($featured_image_value);
+ } else {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ }
} else {
- $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ if (isset($_POST['featured_business_image'])) {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage($_POST['featured_business_image']);
+ } else {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ }
}
Broadstreet_View::load('admin/businesses', array('featured_image' => $featured_image));
@@ -1272,10 +1307,16 @@
{
if(isset($_POST['bs_submit']))
{
+ // Define URL fields that should use esc_url_raw for sanitization
+ $url_fields = array('bs_website', 'bs_menu', 'bs_twitter', 'bs_facebook', 'bs_gplus', 'bs_yelp', 'bs_offer_link');
+
foreach(self::$_businessDefaults as $key => $value)
{
// Special handling for video content - only allow video and iframe tags to prevent XSS attacks
if(isset($_POST[$key]) && $key == 'bs_video') {
+ $original_content = $_POST[$key];
+ $security_warning = false;
+
// Create a whitelist of allowed tags
$allowed_tags = array(
'video' => array(
@@ -1287,7 +1328,9 @@
'muted' => true,
'poster' => true,
'preload' => true,
- 'src' => true
+ 'src' => true,
+ 'class' => true,
+ 'id' => true
),
'source' => array(
'src' => true,
@@ -1299,24 +1342,75 @@
'height' => true,
'frameborder' => true,
'allowfullscreen' => true,
- 'allow' => true
+ 'allow' => true,
+ 'title' => true,
+ 'class' => true,
+ 'id' => true
)
);
-
- // Strip all tags except those in the whitelist
- $video_content = wp_kses($_POST[$key], $allowed_tags);
-
+
+ // Define allowed protocols for URLs (prevent javascript:, data:, etc.)
+ $allowed_protocols = array('http', 'https');
+
+ // Strip all tags except those in the whitelist, with protocol validation
+ $video_content = wp_kses($_POST[$key], $allowed_tags, $allowed_protocols);
+
+ // Check for and remove dangerous patterns
+ // 1. Detect javascript: protocol
+ if (preg_match('/javascript:/i', $original_content)) {
+ $security_warning = true;
+ $video_content = preg_replace('/(<[^>]*[s'"](src|href|poster|data)s*=s*['"]?)javascript:/i', '$1', $video_content);
+ }
+
+ // 2. Detect data: protocol
+ if (preg_match('/data:/i', $original_content)) {
+ $security_warning = true;
+ $video_content = preg_replace('/(<[^>]*[s'"](src|href|poster|data)s*=s*['"]?)data:/i', '$1', $video_content);
+ }
+
+ // 3. Detect and remove event handlers (on*)
+ if (preg_match('/<[^>]*s+onw+s*=/i', $original_content)) {
+ $security_warning = true;
+ $video_content = preg_replace('/<([^>]*)s+onw+s*=s*['"][^'"]*['"]([^>]*)>/i', '<$1$2>', $video_content);
+ }
+
+ // 4. Detect <script> tags
+ if (preg_match('/<script/i', $original_content)) {
+ $security_warning = true;
+ }
+
+ // 5. Clean up any broken/suspicious src attributes after sanitization
+ // This removes leftover garbage from removed javascript:/data: protocols
+ $video_content = preg_replace('/(<(?:iframe|video|source)[^>]*s+srcs*=s*['"])(?!['"]?https?://)[^'"]*(['"])/i', '$1$2', $video_content);
+
// Save the sanitized video content
Broadstreet_Utility::setPostMeta($post_id, $key, $video_content);
-
+
+ // Store security warning flag as transient for admin notice
+ if ($security_warning) {
+ set_transient('broadstreet_video_security_warning_' . get_current_user_id(), true, 45);
+ }
+
// Skip the default handling for this field
continue;
}
- if(isset($_POST[$key]))
- Broadstreet_Utility::setPostMeta($post_id, $key, is_string($_POST[$key]) ? trim($_POST[$key]) : $_POST[$key]);
- elseif($key == 'bs_images')
+ if(isset($_POST[$key])) {
+ // Sanitize input based on field type to prevent XSS attacks
+ if (is_array($_POST[$key])) {
+ // Handle array fields (like bs_images)
+ $sanitized_value = array_map('sanitize_text_field', $_POST[$key]);
+ } elseif (in_array($key, $url_fields)) {
+ // URL fields - use esc_url_raw for database storage
+ $sanitized_value = esc_url_raw(trim($_POST[$key]));
+ } else {
+ // Text fields - use sanitize_text_field to strip tags and encode special chars
+ $sanitized_value = sanitize_text_field(trim($_POST[$key]));
+ }
+ Broadstreet_Utility::setPostMeta($post_id, $key, $sanitized_value);
+ } elseif($key == 'bs_images') {
Broadstreet_Utility::setPostMeta($post_id, $key, self::$_businessDefaults[$key]);
+ }
}
}
}
--- a/broadstreet/Broadstreet/Views/admin/admin.php
+++ b/broadstreet/Broadstreet/Views/admin/admin.php
@@ -90,7 +90,7 @@
</div>
<div class="save-container">
<span class="success" id="save-success">Saved!</span>
- <input id="save-broadstreet" type="button" value="Save" name="" />
+ <input id="save-broadstreet" type="button" value="Save" name="" data-nonce="<?php echo wp_create_nonce('broadstreet_settings_nonce'); ?>" />
</div>
</div>
<div class="clearfix"></div>
@@ -103,4 +103,10 @@
</div>
</div>
<div class="clearfix"></div>
- <!-- <img src="http://report.Broadstreet2.com/checkin/?s=<?php echo $service_tag.'&'.time(); ?>" alt="" /> -->
No newline at end of file
+ <!-- <img src="http://report.Broadstreet2.com/checkin/?s=<?php echo $service_tag.'&'.time(); ?>" alt="" /> -->
+ <script>
+ window.broadstreet_register_nonce = '<?php echo wp_create_nonce('broadstreet_register_nonce'); ?>';
+ window.broadstreet_advertiser_nonce = '<?php echo wp_create_nonce('broadstreet_advertiser_nonce'); ?>';
+ window.broadstreet_facebook_nonce = '<?php echo wp_create_nonce('broadstreet_facebook_nonce'); ?>';
+ window.broadstreet_zone_settings_nonce = '<?php echo wp_create_nonce('broadstreet_zone_settings_nonce'); ?>';
+ </script>
No newline at end of file
--- a/broadstreet/Broadstreet/Views/admin/businessMetaBox.php
+++ b/broadstreet/Broadstreet/Views/admin/businessMetaBox.php
@@ -266,4 +266,8 @@
<input type="hidden" name="bs_submit" value="1" />
<script src="<?php echo esc_url(Broadstreet_Utility::getVendorBaseURL()) ?>jquery/jquery-ui-1.9.1.sortable-custom.min.js"></script>
-<script>window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;</script>
+<script>
+window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;
+window.broadstreet_advertiser_nonce = '<?php echo wp_create_nonce('broadstreet_advertiser_nonce'); ?>';
+window.broadstreet_facebook_nonce = '<?php echo wp_create_nonce('broadstreet_facebook_nonce'); ?>';
+</script>
--- a/broadstreet/Broadstreet/Views/admin/businesses.php
+++ b/broadstreet/Broadstreet/Views/admin/businesses.php
@@ -1,5 +1,6 @@
<script src="https://broadstreet-common.s3.amazonaws.com/broadstreet-net/init.js"></script>
<form method="post">
+ <?php wp_nonce_field('broadstreet_business_nonce'); ?>
<div id="main">
<?php Broadstreet_View::load('admin/global/header') ?>
<div class="left_column">
--- a/broadstreet/Broadstreet/Views/admin/sponsoredBox.php
+++ b/broadstreet/Broadstreet/Views/admin/sponsoredBox.php
@@ -91,7 +91,7 @@
var el = document.getElementById('bs_sponsor_old_advertisement_id');
var post_id = editor.getCurrentPostId();
- jQuery.get(window.ajaxurl + '?action=get_sponsored_meta&post_id=' + post_id, function (data) {
+ jQuery.get(window.ajaxurl + '?action=get_sponsored_meta&post_id=' + post_id + '&nonce=' + broadstreetAjax.nonce, function (data) {
var meta = data.meta;
console.info('Broadstreet Meta Update ...', meta);
if (meta.bs_sponsor_is_sponsored == '1') {
@@ -121,4 +121,7 @@
and make sure your access token is correct, and make sure you have zones set up.</p>
<?php endif; ?>
<input type="hidden" name="bs_sponsor_submit" value="1" />
-<script>window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;</script>
No newline at end of file
+<script>
+window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;
+window.broadstreet_sponsor_nonce = '<?php echo wp_create_nonce('broadstreet_sponsor_nonce'); ?>';
+</script>
No newline at end of file
--- a/broadstreet/Broadstreet/Views/admin/zones.php
+++ b/broadstreet/Broadstreet/Views/admin/zones.php
@@ -7,7 +7,10 @@
try {
// --- START OF ORIGINAL PAGE CONTENT ---
?>
-<script>window.bs_bootstrap = <?php echo json_encode($data); ?>;</script>
+<script>
+window.bs_bootstrap = <?php echo json_encode($data); ?>;
+window.broadstreet_zone_settings_nonce = '<?php echo wp_create_nonce('broadstreet_zone_settings_nonce'); ?>';
+</script>
<div id="main" ng-app="bs_zones">
<?php Broadstreet_View::load('admin/global/header') ?>
<div class="left_column" ng-controller="ZoneCtrl">
@@ -460,7 +463,7 @@
console.log('Saving settings:', $scope.data.positions_zones);
$scope.loadingMessage = 'Saving ...';
var params = $scope.data.positions_zones;
- $http.post(window.ajaxurl + '?action=save_zone_settings', params)
+ $http.post(window.ajaxurl + '?action=save_zone_settings&nonce=' + broadstreetAjax.nonce, params)
.success(function(response) {
$scope.loadingMessage = null;
var saveSuccessEl = document.getElementById('save-success');
--- a/broadstreet/Broadstreet/Views/listings/archive/default.php
+++ b/broadstreet/Broadstreet/Views/listings/archive/default.php
@@ -50,15 +50,15 @@
<?php endif; ?>
<div class="biz-column-1">
<?php if(count($meta['bs_images'])): ?>
- <img class="boxed-sizing" src="<?php echo $meta['bs_images'][0] ?>" alt="" width="100%" />
+ <img class="boxed-sizing" src="<?php echo esc_url($meta['bs_images'][0]) ?>" alt="" width="100%" />
<div></div>
<?php endif; ?>
<div class="basic-info">
<?php if($meta['bs_address']): ?>
- <?php echo nl2br($meta['bs_address']) ?><br />
+ <?php echo nl2br(esc_html($meta['bs_address'])) ?><br />
<?php endif; ?>
- <?php if($meta['bs_phone']): ?>
- <?php echo $meta['bs_phone'] ?>
+ <?php if($meta['bs_phone']): ?>
+ <?php echo esc_html($meta['bs_phone']) ?>
<?php endif; ?>
</div>
</div>
@@ -66,26 +66,26 @@
<?php echo wp_trim_words(strip_tags($content), 100); ?> <a href="<?php the_permalink() ?>">Read More</a>
<?php $day = strtolower(date('l')); ?>
<?php if($meta["bs_{$day}_open"]): ?>
- <div><strong>Open today</strong> <?php echo $meta["bs_{$day}_open"] . ' to ' . $meta["bs_{$day}_close"]; ?>.
+ <div><strong>Open today</strong> <?php echo esc_html($meta["bs_{$day}_open"]) . ' to ' . esc_html($meta["bs_{$day}_close"]); ?>.
<?php if($meta['bs_menu']): ?>
- <a href="<?php echo $meta['bs_menu'] ?>">View a menu</a>
- <?php endif; ?>
+ <a href="<?php echo esc_url($meta['bs_menu']) ?>">View a menu</a>
+ <?php endif; ?>
</div>
- <?php echo get_the_term_list($GLOBALS['post']->ID, Broadstreet_Core::BIZ_TAXONOMY, 'Posted in: ', ', ', '') ?>
+ <?php echo get_the_term_list($GLOBALS['post']->ID, Broadstreet_Core::BIZ_TAXONOMY, 'Posted in: ', ', ', '') ?>
<?php endif; ?>
<?php if($meta['bs_twitter'] || $meta['bs_twitter'] || $meta['bs_yelp']): ?>
<p class="bs-social">
<?php if($meta['bs_twitter']): ?>
- <a target="_blank" href="<?php echo $meta['bs_twitter'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'twitter.png' ?>" alt="twitter" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_twitter']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'twitter.png') ?>" alt="twitter" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_facebook']): ?>
- <a target="_blank" href="<?php echo $meta['bs_facebook'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'facebook.png' ?>" alt="facebook" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_facebook']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'facebook.png') ?>" alt="facebook" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_gplus']): ?>
- <a target="_blank" href="<?php echo $meta['bs_gplus'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'google.png' ?>" alt="Google Plus" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_gplus']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'google.png') ?>" alt="Google Plus" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_yelp']): ?>
- <a target="_blank" href="<?php echo $meta['bs_yelp'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'yelp.png' ?>" alt="yelp" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_yelp']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'yelp.png') ?>" alt="yelp" width="20" /></a>
<?php endif; ?>
</p>
<?php endif; ?>
--- a/broadstreet/broadstreet.php
+++ b/broadstreet/broadstreet.php
@@ -3,7 +3,7 @@
Plugin Name: Broadstreet
Plugin URI: http://broadstreetads.com
Description: Integrate Broadstreet business directory and adserving power into your site
-Version: 1.52.2
+Version: 1.53.2
Tested up to: 6.9
Author: Broadstreet
Author URI: http://broadstreetads.com
--- a/broadstreet/trunk/Broadstreet/Ajax.php
+++ b/broadstreet/trunk/Broadstreet/Ajax.php
@@ -26,6 +26,7 @@
wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
}
+
// Sanitize the API key before storing it
$api_key = sanitize_text_field($_POST['api_key']);
Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $api_key);
@@ -105,11 +106,14 @@
wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
}
+
$api_key = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_API_KEY);
$network_id = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_NETWORK_ID);
$api = Broadstreet_Utility::getBroadstreetClient();
- $advertiser = $api->createAdvertiser($network_id, stripslashes($_POST['name']));
+ // Sanitize advertiser name to prevent XSS
+ $name = sanitize_text_field(stripslashes($_POST['name']));
+ $advertiser = $api->createAdvertiser($network_id, $name);
die(json_encode(array('success' => true, 'advertiser' => $advertiser)));
}
@@ -123,6 +127,15 @@
}
$post_id = isset($_GET['post_id']) ? intval($_GET['post_id']) : 0;
+
+ // Verify user has permission to edit this post (fixes IDOR vulnerability)
+ if (!current_user_can('edit_post', $post_id)) {
+ die(json_encode(array('success' => false, 'error' => 'Permission denied')));
+ }
+
+ // Verify nonce and referer (fixes CSRF vulnerability)
+ check_ajax_referer('broadstreet_sponsor_nonce', '_wpnonce');
+
die(json_encode(array('success' => true, 'meta' => Broadstreet_Utility::getAllPostMeta($post_id))));
}
@@ -135,9 +148,11 @@
wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
}
+ $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
+
try
{
- $profile = Broadstreet_Utility::importBusiness($_POST['id'], $_POST['post_id']);
+ $profile = Broadstreet_Utility::importBusiness(sanitize_text_field($_POST['id']), $post_id);
die(json_encode(array('success' => (bool)$profile, 'profile' => $profile)));
}
catch(Broadstreet_ServerException $ex)
@@ -155,12 +170,13 @@
wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
}
+
$api = Broadstreet_Utility::getBroadstreetClient(true);
try
{
# Register the user by email address
- $resp = $api->register($_POST['email']);
+ $resp = $api->register(sanitize_email($_POST['email']));
Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $resp->access_token);
# Create a network for the new user
--- a/broadstreet/trunk/Broadstreet/Config.php
+++ b/broadstreet/trunk/Broadstreet/Config.php
@@ -140,4 +140,4 @@
}
}
-define('BROADSTREET_VERSION', '1.52.2');
+define('BROADSTREET_VERSION', '1.53.2');
--- a/broadstreet/trunk/Broadstreet/Core.php
+++ b/broadstreet/trunk/Broadstreet/Core.php
@@ -465,7 +465,14 @@
'page'
);
- $screens = get_post_types();
+ /**
+ * Filter the post types on which Broadstreet meta boxes appear.
+ * Defaults to all registered post types.
+ *
+ * @param array $post_types Array of post type slugs.
+ */
+ $screens = apply_filters('broadstreet_meta_box_post_types', get_post_types());
+
if (Broadstreet_Utility::getOption(self::KEY_API_KEY)) {
foreach ( $screens as $screen ) {
add_meta_box(
@@ -473,8 +480,8 @@
__( '<span class="dashicons dashicons-performance"></span> Sponsored Content', 'broadstreet_textdomain'),
array($this, 'broadstreetSponsoredBox'),
$screen,
- 'side',
- 'high'
+ apply_filters('broadstreet_sponsored_meta_box_context', 'side', $screen),
+ apply_filters('broadstreet_sponsored_meta_box_priority', 'high', $screen)
);
}
}
@@ -485,7 +492,8 @@
__( '<span class="dashicons dashicons-format-image"></span> Broadstreet Options', 'broadstreet_textdomain'),
array($this, 'broadstreetAdVisibilityBox'),
$screen,
- 'side'
+ apply_filters('broadstreet_options_meta_box_context', 'side', $screen),
+ apply_filters('broadstreet_options_meta_box_priority', 'default', $screen)
);
}
@@ -496,7 +504,8 @@
__( 'Business Details', 'broadstreet_textdomain'),
array($this, 'broadstreetBusinessBox'),
self::BIZ_POST_TYPE,
- 'normal'
+ apply_filters('broadstreet_business_meta_box_context', 'normal'),
+ apply_filters('broadstreet_business_meta_box_priority', 'default')
);
}
}
@@ -829,11 +838,29 @@
}
public function adminMenuBusinessCallback() {
-
- if (isset($_POST['featured_business_image'])) {
- $featured_image = Broadstreet_Utility::featuredBusinessImage($_POST['featured_business_image']);
+ // Handle POSTed settings securely
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Require capability
+ if (!current_user_can('manage_options')) {
+ wp_die('Permission denied');
+ }
+
+ // Verify nonce for the businesses settings form
+ check_admin_referer('broadstreet_business_nonce');
+
+ // Sanitize and persist the featured image setting
+ if (isset($_POST['featured_business_image'])) {
+ $featured_image_value = sanitize_text_field($_POST['featured_business_image']);
+ $featured_image = Broadstreet_Utility::featuredBusinessImage($featured_image_value);
+ } else {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ }
} else {
- $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ if (isset($_POST['featured_business_image'])) {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage($_POST['featured_business_image']);
+ } else {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ }
}
Broadstreet_View::load('admin/businesses', array('featured_image' => $featured_image));
@@ -1289,6 +1316,9 @@
{
if(isset($_POST['bs_submit']))
{
+ // Define URL fields that should use esc_url_raw for sanitization
+ $url_fields = array('bs_website', 'bs_menu', 'bs_twitter', 'bs_facebook', 'bs_gplus', 'bs_yelp', 'bs_offer_link');
+
foreach(self::$_businessDefaults as $key => $value)
{
// Special handling for video content - only allow video and iframe tags to prevent XSS attacks
@@ -1374,10 +1404,22 @@
continue;
}
- if(isset($_POST[$key]))
- Broadstreet_Utility::setPostMeta($post_id, $key, is_string($_POST[$key]) ? trim($_POST[$key]) : $_POST[$key]);
- elseif($key == 'bs_images')
+ if(isset($_POST[$key])) {
+ // Sanitize input based on field type to prevent XSS attacks
+ if (is_array($_POST[$key])) {
+ // Handle array fields (like bs_images)
+ $sanitized_value = array_map('sanitize_text_field', $_POST[$key]);
+ } elseif (in_array($key, $url_fields)) {
+ // URL fields - use esc_url_raw for database storage
+ $sanitized_value = esc_url_raw(trim($_POST[$key]));
+ } else {
+ // Text fields - use sanitize_text_field to strip tags and encode special chars
+ $sanitized_value = sanitize_text_field(trim($_POST[$key]));
+ }
+ Broadstreet_Utility::setPostMeta($post_id, $key, $sanitized_value);
+ } elseif($key == 'bs_images') {
Broadstreet_Utility::setPostMeta($post_id, $key, self::$_businessDefaults[$key]);
+ }
}
}
}
--- a/broadstreet/trunk/Broadstreet/Views/admin/admin.php
+++ b/broadstreet/trunk/Broadstreet/Views/admin/admin.php
@@ -90,7 +90,7 @@
</div>
<div class="save-container">
<span class="success" id="save-success">Saved!</span>
- <input id="save-broadstreet" type="button" value="Save" name="" />
+ <input id="save-broadstreet" type="button" value="Save" name="" data-nonce="<?php echo wp_create_nonce('broadstreet_settings_nonce'); ?>" />
</div>
</div>
<div class="clearfix"></div>
@@ -103,4 +103,10 @@
</div>
</div>
<div class="clearfix"></div>
- <!-- <img src="http://report.Broadstreet2.com/checkin/?s=<?php echo $service_tag.'&'.time(); ?>" alt="" /> -->
No newline at end of file
+ <!-- <img src="http://report.Broadstreet2.com/checkin/?s=<?php echo $service_tag.'&'.time(); ?>" alt="" /> -->
+ <script>
+ window.broadstreet_register_nonce = '<?php echo wp_create_nonce('broadstreet_register_nonce'); ?>';
+ window.broadstreet_advertiser_nonce = '<?php echo wp_create_nonce('broadstreet_advertiser_nonce'); ?>';
+ window.broadstreet_facebook_nonce = '<?php echo wp_create_nonce('broadstreet_facebook_nonce'); ?>';
+ window.broadstreet_zone_settings_nonce = '<?php echo wp_create_nonce('broadstreet_zone_settings_nonce'); ?>';
+ </script>
No newline at end of file
--- a/broadstreet/trunk/Broadstreet/Views/admin/businessMetaBox.php
+++ b/broadstreet/trunk/Broadstreet/Views/admin/businessMetaBox.php
@@ -266,4 +266,8 @@
<input type="hidden" name="bs_submit" value="1" />
<script src="<?php echo esc_url(Broadstreet_Utility::getVendorBaseURL()) ?>jquery/jquery-ui-1.9.1.sortable-custom.min.js"></script>
-<script>window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;</script>
+<script>
+window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;
+window.broadstreet_advertiser_nonce = '<?php echo wp_create_nonce('broadstreet_advertiser_nonce'); ?>';
+window.broadstreet_facebook_nonce = '<?php echo wp_create_nonce('broadstreet_facebook_nonce'); ?>';
+</script>
--- a/broadstreet/trunk/Broadstreet/Views/admin/businesses.php
+++ b/broadstreet/trunk/Broadstreet/Views/admin/businesses.php
@@ -1,5 +1,6 @@
<script src="https://broadstreet-common.s3.amazonaws.com/broadstreet-net/init.js"></script>
<form method="post">
+ <?php wp_nonce_field('broadstreet_business_nonce'); ?>
<div id="main">
<?php Broadstreet_View::load('admin/global/header') ?>
<div class="left_column">
--- a/broadstreet/trunk/Broadstreet/Views/admin/sponsoredBox.php
+++ b/broadstreet/trunk/Broadstreet/Views/admin/sponsoredBox.php
@@ -121,4 +121,7 @@
and make sure your access token is correct, and make sure you have zones set up.</p>
<?php endif; ?>
<input type="hidden" name="bs_sponsor_submit" value="1" />
-<script>window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;</script>
No newline at end of file
+<script>
+window.bs_post_id = <?php echo (int)$GLOBALS['post']->ID ?>;
+window.broadstreet_sponsor_nonce = '<?php echo wp_create_nonce('broadstreet_sponsor_nonce'); ?>';
+</script>
No newline at end of file
--- a/broadstreet/trunk/Broadstreet/Views/admin/zones.php
+++ b/broadstreet/trunk/Broadstreet/Views/admin/zones.php
@@ -7,7 +7,10 @@
try {
// --- START OF ORIGINAL PAGE CONTENT ---
?>
-<script>window.bs_bootstrap = <?php echo json_encode($data); ?>;</script>
+<script>
+window.bs_bootstrap = <?php echo json_encode($data); ?>;
+window.broadstreet_zone_settings_nonce = '<?php echo wp_create_nonce('broadstreet_zone_settings_nonce'); ?>';
+</script>
<div id="main" ng-app="bs_zones">
<?php Broadstreet_View::load('admin/global/header') ?>
<div class="left_column" ng-controller="ZoneCtrl">
--- a/broadstreet/trunk/Broadstreet/Views/listings/archive/default.php
+++ b/broadstreet/trunk/Broadstreet/Views/listings/archive/default.php
@@ -50,15 +50,15 @@
<?php endif; ?>
<div class="biz-column-1">
<?php if(count($meta['bs_images'])): ?>
- <img class="boxed-sizing" src="<?php echo $meta['bs_images'][0] ?>" alt="" width="100%" />
+ <img class="boxed-sizing" src="<?php echo esc_url($meta['bs_images'][0]) ?>" alt="" width="100%" />
<div></div>
<?php endif; ?>
<div class="basic-info">
<?php if($meta['bs_address']): ?>
- <?php echo nl2br($meta['bs_address']) ?><br />
+ <?php echo nl2br(esc_html($meta['bs_address'])) ?><br />
<?php endif; ?>
- <?php if($meta['bs_phone']): ?>
- <?php echo $meta['bs_phone'] ?>
+ <?php if($meta['bs_phone']): ?>
+ <?php echo esc_html($meta['bs_phone']) ?>
<?php endif; ?>
</div>
</div>
@@ -66,26 +66,26 @@
<?php echo wp_trim_words(strip_tags($content), 100); ?> <a href="<?php the_permalink() ?>">Read More</a>
<?php $day = strtolower(date('l')); ?>
<?php if($meta["bs_{$day}_open"]): ?>
- <div><strong>Open today</strong> <?php echo $meta["bs_{$day}_open"] . ' to ' . $meta["bs_{$day}_close"]; ?>.
+ <div><strong>Open today</strong> <?php echo esc_html($meta["bs_{$day}_open"]) . ' to ' . esc_html($meta["bs_{$day}_close"]); ?>.
<?php if($meta['bs_menu']): ?>
- <a href="<?php echo $meta['bs_menu'] ?>">View a menu</a>
- <?php endif; ?>
+ <a href="<?php echo esc_url($meta['bs_menu']) ?>">View a menu</a>
+ <?php endif; ?>
</div>
- <?php echo get_the_term_list($GLOBALS['post']->ID, Broadstreet_Core::BIZ_TAXONOMY, 'Posted in: ', ', ', '') ?>
+ <?php echo get_the_term_list($GLOBALS['post']->ID, Broadstreet_Core::BIZ_TAXONOMY, 'Posted in: ', ', ', '') ?>
<?php endif; ?>
<?php if($meta['bs_twitter'] || $meta['bs_twitter'] || $meta['bs_yelp']): ?>
<p class="bs-social">
<?php if($meta['bs_twitter']): ?>
- <a target="_blank" href="<?php echo $meta['bs_twitter'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'twitter.png' ?>" alt="twitter" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_twitter']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'twitter.png') ?>" alt="twitter" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_facebook']): ?>
- <a target="_blank" href="<?php echo $meta['bs_facebook'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'facebook.png' ?>" alt="facebook" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_facebook']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'facebook.png') ?>" alt="facebook" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_gplus']): ?>
- <a target="_blank" href="<?php echo $meta['bs_gplus'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'google.png' ?>" alt="Google Plus" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_gplus']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'google.png') ?>" alt="Google Plus" width="20" /></a>
<?php endif; ?>
<?php if($meta['bs_yelp']): ?>
- <a target="_blank" href="<?php echo $meta['bs_yelp'] ?>"><img src="<?php echo Broadstreet_Utility::getImageBaseURL().'yelp.png' ?>" alt="yelp" width="20" /></a>
+ <a target="_blank" href="<?php echo esc_url($meta['bs_yelp']) ?>"><img src="<?php echo esc_url(Broadstreet_Utility::getImageBaseURL().'yelp.png') ?>" alt="yelp" width="20" /></a>
<?php endif; ?>
</p>
<?php endif; ?>
--- a/broadstreet/trunk/broadstreet.php
+++ b/broadstreet/trunk/broadstreet.php
@@ -3,8 +3,8 @@
Plugin Name: Broadstreet
Plugin URI: http://broadstreetads.com
Description: Integrate Broadstreet business directory and adserving power into your site
-Version: 1.52.2
-Tested up to: 6.6.1
+Version: 1.53.2
+Tested up to: 6.9
Author: Broadstreet
Author URI: http://broadstreetads.com
*/