CWE-89• Year: 2025
Analyzed CVEs:CVE-2025-11893,CVE-2025-22783,CVE-2025-49378,CVE-2025-10142,CVE-2025-10037
--- cache/featured-image-from-url_5.2.7/admin/cron.php 2025-11-19 10:52:43.032414275 +0000+++ cache/featured-image-from-url_5.2.8/admin/cron.php 2025-11-19 10:52:44.547511393 +0000@@ -65,17 +65,6 @@ update_option($field, true, 'no'); } -function fifu_should_stop_job($option_name) {- $field = $option_name . '_stop';-- global $wpdb;- if ($wpdb->get_col("SELECT 1 FROM " . $wpdb->options . " WHERE option_name = '" . $field . "'")) {- delete_option($field);- return true;- }- return false;-}- function fifu_run_cron_now() { wp_remote_request(site_url('wp-cron.php')); }
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - admin/cron.php Lines 68-71
Old Code:
```
global $wpdb;
if ($wpdb->get_col("SELECT 1 FROM " . $wpdb->options . " WHERE option_name = '" . $field . "'")) {
delete_option($field);
return true;
}
```
Fixed Code:
```
// Function removed entirely
```
Explanation:
The deleted function contained a SQL injection vulnerability. User input enters through the `$option_name` parameter, which is concatenated into `$field`. The `$field` variable is then directly concatenated into a SQL query string without any sanitization or parameterization. The query is executed via `$wpdb->get_col()`. Since `$option_name` is attacker-controlled and reaches the SQL sink unsanitized, this constitutes a SQL injection vulnerability. The function was completely removed in the new version, eliminating the vulnerability.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/admin/db.php 2025-11-19 10:52:43.033414340 +0000+++ cache/featured-image-from-url_5.2.8/admin/db.php 2025-11-19 10:52:44.548511457 +0000@@ -34,9 +34,110 @@ $this->types = $this->get_types(); } - function get_types() {- $post_types = fifu_get_post_types();- return join("','", $post_types);+ function get_types(): string {+ $raw = (array) fifu_get_post_types();++ // Sanitize and validate against registered post types+ $registered = get_post_types([], 'names'); // array of valid names+ $safe = [];+ foreach ($raw as $pt) {+ $pt = sanitize_key($pt);+ if ($pt !== '' && isset($registered[$pt])) {+ $safe[] = $pt;+ }+ }+ // Deduplicate while preserving order+ $safe = array_values(array_unique($safe));+ return implode("','", $safe);+ }++ function sanitize_ids_csv($ids, bool $allow_zero = false): string {+ // Normalize $ids to an array+ if (is_string($ids)) {+ $ids = explode(',', $ids);+ } elseif (is_int($ids)) {+ $ids = [$ids];+ } elseif (!is_array($ids)) {+ $ids = [];+ }++ $set = [];+ foreach ($ids as $id) {+ if (is_int($id)) {+ $n = $id;+ } elseif (is_string($id)) {+ $id = trim($id);+ if ($id === '' || !ctype_digit($id)) { // digits only+ continue;+ }+ $n = (int) $id; // safe after ctype_digit+ } else {+ continue;+ }++ if ($n > 0 || ($allow_zero && $n === 0)) {+ $set[$n] = true; // dedupe+ }+ }++ if (!$set) {+ return '0'; // ensures valid "IN (0)" => no matches+ }++ return implode(',', array_keys($set));+ }++ // Sanitize a list of post types (array or CSV string) for safe IN (...) usage+ function sanitize_post_types_list($post_types) {+ // Normalize input to array+ if (is_string($post_types)) {+ $post_types = explode(',', str_replace(['"', "'"], '', $post_types));+ } elseif (!is_array($post_types)) {+ $post_types = [];+ }++ // Whitelist of registered post types+ $registered = array_flip(get_post_types([], 'names'));++ // Sanitize + dedupe+ $set = [];+ foreach ($post_types as $pt) {+ $pt = sanitize_key(trim((string) $pt)); // [a-z0-9_-], lowercased+ if ($pt === '' || !isset($registered[$pt])) {+ continue;+ }+ $set[$pt] = true;+ }++ if (!$set) {+ // If used in a class context that defines $this->types, keep compatibility+ if (isset($this) && isset($this->types) && is_string($this->types) && $this->types !== '') {+ return $this->types;+ }+ // Safe default: match nothing+ return "''";+ }++ $items = array_keys($set);+ // sanitize_key already guarantees safe charset; quoting is enough for IN (...)+ return "'" . implode("','", $items) . "'";+ }++ function build_in_from_option_csv(string $base_key, string $option_name): array {+ $field = (string) get_option($option_name);++ $keys = [$base_key];+ if ($field !== '') {+ foreach (explode(',', $field) as $k) {+ $k = trim($k);+ if ($k !== '')+ $keys[] = $k;+ }+ }+ $keys = array_values(array_unique($keys));++ $in = implode(',', array_fill(0, count($keys), '%s')); // e.g. ['fifu_isbn','custom1'] -> IN ('fifu_isbn','custom1')+ return [$in, $keys]; } /* attachment metadata */@@ -44,15 +145,17 @@ // delete 1 _wp_attached_file or _wp_attachment_image_alt for each attachment function delete_attachment_meta($ids, $is_ctgr) { $ctgr_sql = $is_ctgr ? "AND p.post_name LIKE 'fifu-category%'" : "";-- $this->wpdb->query("+ $ids_csv = $this->sanitize_ids_csv($ids);+ $author = $this->author;+ $sql = " DELETE pm FROM {$this->postmeta} pm JOIN {$this->posts} p ON pm.post_id = p.id WHERE pm.meta_key IN ('_wp_attached_file', '_wp_attachment_image_alt', '_wp_attachment_metadata')- AND p.post_parent IN ({$ids})- AND p.post_author = {$this->author} + AND p.post_parent IN ({$ids_csv})+ AND p.post_author = %d {$ctgr_sql}- ");+ ";+ $this->wpdb->query($this->wpdb->prepare($sql, $author)); } function insert_thumbnail_id_ctgr($ids, $is_ctgr) {@@ -72,32 +175,35 @@ // has attachment created by FIFU function is_fifu_attachment($att_id) {- return $this->wpdb->get_row("- SELECT 1 - FROM {$this->posts} - WHERE id = {$att_id} - AND post_author = {$this->author}"- ) != null;+ $sql = $this->wpdb->prepare(+ "SELECT 1 FROM {$this->posts} WHERE id = %d AND post_author = %d",+ (int) $att_id,+ $this->author+ );+ return $this->wpdb->get_row($sql) != null; } // get att_id by post and url function get_att_id($post_parent, $url, $is_ctgr) { $ctgr_sql = $is_ctgr ? "AND p.post_name LIKE 'fifu-category%'" : "";- $result = $this->wpdb->get_results("- SELECT pm.post_id- FROM {$this->postmeta} pm- WHERE pm.meta_key = '_wp_attached_file'- AND pm.meta_value = '{$url}'- AND pm.post_id IN (- SELECT p.id- FROM {$this->posts} p - WHERE p.post_parent = {$post_parent}- AND post_author = {$this->author}- {$ctgr_sql} - )- LIMIT 1- ");- return $result ? $result[0]->post_id : null;+ $sql = $this->wpdb->prepare(+ "SELECT pm.post_id+ FROM {$this->postmeta} pm+ WHERE pm.meta_key = '_wp_attached_file'+ AND pm.meta_value = %s+ AND pm.post_id IN (+ SELECT p.id+ FROM {$this->posts} p + WHERE p.post_parent = %d+ AND post_author = %d {$ctgr_sql}+ )+ LIMIT 1",+ $url,+ (int) $post_parent,+ $this->author+ );+ $row = $this->wpdb->get_row($sql);+ return $row ? (int) $row->post_id : null; } function get_count_wp_postmeta() {@@ -115,25 +221,25 @@ } function get_count_wp_posts_fifu() {- return $this->wpdb->get_results("- SELECT COUNT(1) AS amount- FROM {$this->posts}- WHERE post_author = {$this->author}- ");+ $sql = $this->wpdb->prepare(+ "SELECT COUNT(1) AS amount FROM {$this->posts} WHERE post_author = %d",+ $this->author+ );+ return $this->wpdb->get_results($sql); } function get_count_wp_postmeta_fifu() {- return $this->wpdb->get_results("- SELECT COUNT(1) AS amount- FROM {$this->postmeta}- WHERE meta_key = '_wp_attached_file'- AND EXISTS (- SELECT 1- FROM {$this->posts}- WHERE id = post_id- AND post_author = {$this->author}- )- ");+ $sql = $this->wpdb->prepare(+ "SELECT COUNT(1) AS amount+ FROM {$this->postmeta}+ WHERE meta_key = '_wp_attached_file'+ AND EXISTS (+ SELECT 1 FROM {$this->posts}+ WHERE id = post_id AND post_author = %d+ )",+ $this->author+ );+ return $this->wpdb->get_results($sql); } function tables_created() {@@ -141,19 +247,29 @@ } function debug_slug($slug) {- $sql = $this->wpdb->prepare("SELECT ID, post_author, post_content, post_title, post_status, post_parent, post_content_filtered, guid, post_type FROM {$this->posts} WHERE post_name = %s", $slug);+ $sql = $this->wpdb->prepare(+ "SELECT ID, post_author, post_content, post_title, post_status, post_parent, post_content_filtered, guid, post_type + FROM {$this->posts} + WHERE post_name = %s+ AND post_status <> 'private'+ AND (post_password = '' OR post_password IS NULL)",+ $slug+ ); return $this->wpdb->get_results($sql); } function debug_postmeta($post_id) { $sql = $this->wpdb->prepare("- SELECT meta_key, meta_value- FROM {$this->postmeta} - WHERE post_id = %d - AND (- meta_key LIKE 'fifu%'- OR meta_key IN ('_thumbnail_id', '_wp_attached_file', '_wp_attachment_image_alt', '_product_image_gallery', '_wc_additional_variation_images')- )"+ SELECT pm.meta_key, pm.meta_value+ FROM {$this->postmeta} pm+ INNER JOIN {$this->posts} p ON p.ID = pm.post_id+ WHERE pm.post_id = %d + AND p.post_status <> 'private'+ AND (p.post_password = '' OR p.post_password IS NULL)+ AND (+ pm.meta_key LIKE 'fifu%'+ OR pm.meta_key IN ('_thumbnail_id', '_wp_attached_file', '_wp_attachment_image_alt', '_product_image_gallery', '_wc_additional_variation_images')+ )" , $post_id); return $this->wpdb->get_results($sql); }@@ -162,24 +278,27 @@ $sql = $this->wpdb->prepare(" SELECT post_author, post_content, post_title, post_status, post_parent, post_content_filtered, guid, post_type FROM {$this->posts} - WHERE id = %d"+ WHERE id = %d+ AND post_status <> 'private'+ AND (post_password = '' OR post_password IS NULL)" , $id); return $this->wpdb->get_results($sql); } function debug_metain() {- $sql = $this->wpdb->prepare("SELECT * FROM {$this->fifu_meta_in}");- return $this->wpdb->get_results($sql);+ // No placeholders here; do not call prepare()+ return $this->wpdb->get_results("SELECT * FROM {$this->fifu_meta_in}"); } function debug_metaout() {- $sql = $this->wpdb->prepare("SELECT * FROM {$this->fifu_meta_out}");- return $this->wpdb->get_results($sql);+ // No placeholders here; do not call prepare()+ return $this->wpdb->get_results("SELECT * FROM {$this->fifu_meta_out}"); } // count images without dimensions function get_count_posts_without_dimensions() {- return $this->wpdb->get_results("+ $author = $this->author;+ $sql = $this->wpdb->prepare(" SELECT COUNT(1) AS amount FROM {$this->posts} p WHERE NOT EXISTS (@@ -187,36 +306,41 @@ FROM {$this->postmeta} b WHERE p.id = b.post_id AND meta_key = '_wp_attachment_metadata' )- AND p.post_author = {$this->author}- ");+ AND p.post_author = %d+ ", $author);+ return $this->wpdb->get_results($sql); } // count urls with metadata function get_count_urls_with_metadata() {- return $this->wpdb->get_results("+ $author = $this->author;+ $sql = $this->wpdb->prepare(" SELECT COUNT(1) AS amount FROM {$this->posts} p- WHERE p.post_author = {$this->author}- ");+ WHERE p.post_author = %d+ ", $author);+ return $this->wpdb->get_results($sql); } - // count urls+ // Count URLs across postmeta and termmeta (no UNION; no meta_value filters; no tm '%list%' filter) function get_count_urls() {- return $this->wpdb->get_results("- SELECT SUM(id) AS amount- FROM (- SELECT count(post_id) AS id- FROM {$this->postmeta} pm- WHERE pm.meta_key LIKE 'fifu_%'- AND pm.meta_key LIKE '%url%'- AND pm.meta_key NOT LIKE '%list%'- UNION - SELECT count(term_id) AS id- FROM {$this->termmeta} tm- WHERE tm.meta_key LIKE 'fifu_%'- AND tm.meta_key LIKE '%url%'- ) x- ");+ $sql = "+ SELECT+ (+ SELECT COUNT(*)+ FROM {$this->postmeta} AS pm+ WHERE pm.meta_key LIKE 'fifu!_%' ESCAPE '!'+ AND pm.meta_key LIKE '%url%'+ AND pm.meta_key NOT LIKE '%list%'+ ) ++ (+ SELECT COUNT(*)+ FROM {$this->termmeta} AS tm+ WHERE tm.meta_key LIKE 'fifu!_%' ESCAPE '!'+ AND tm.meta_key LIKE '%url%'+ ) AS amount+ ";+ return (int) $this->wpdb->get_var($sql); } function get_count_metadata_operations() {@@ -249,14 +373,16 @@ // get last (images/videos/sliders) function get_last($meta_key) {- return $this->wpdb->get_results("- SELECT p.id, pm.meta_value+ $sql = $this->wpdb->prepare(+ "SELECT p.id, pm.meta_value FROM {$this->posts} p INNER JOIN {$this->postmeta} pm ON p.id = pm.post_id- WHERE pm.meta_key = '{$meta_key}'+ WHERE pm.meta_key = %s ORDER BY p.post_date DESC- LIMIT 3- ");+ LIMIT 3",+ $meta_key+ );+ return $this->wpdb->get_results($sql); } function get_last_image() {@@ -269,50 +395,60 @@ "); } - // get attachments without post+ // get child posts (excluding the featured image) for a given post function get_attachments_without_post($post_id) {- $result = $this->wpdb->get_results("- SELECT GROUP_CONCAT(id) AS ids - FROM {$this->posts} - WHERE post_parent = {$post_id} - AND post_author = {$this->author}- AND post_name NOT LIKE 'fifu-category%' + $sql = $this->wpdb->prepare(+ "SELECT GROUP_CONCAT(p.ID) AS ids+ FROM {$this->posts} p+ WHERE p.post_parent = %d+ AND p.post_author = %d+ AND p.post_name NOT LIKE %s AND NOT EXISTS (- SELECT 1- FROM {$this->postmeta}- WHERE post_id = post_parent- AND meta_key = '_thumbnail_id'- AND meta_value = id- )- GROUP BY post_parent- ");- return $result ? $result[0]->ids : null;+ SELECT 1+ FROM {$this->postmeta} pm2+ WHERE pm2.post_id = p.post_parent+ AND pm2.meta_key = '_thumbnail_id'+ AND pm2.meta_value = p.ID+ )",+ (int) $post_id,+ (int) $this->author,+ 'fifu-category%' // no need for %% since it's a %s value+ );++ // One row expected; return CSV string or null+ $ids_csv = $this->wpdb->get_var($sql);+ return $ids_csv ?: null; } function get_ctgr_attachments_without_post($term_id) {- $result = $this->wpdb->get_results("- SELECT GROUP_CONCAT(id) AS ids - FROM {$this->posts} - WHERE post_parent = {$term_id} - AND post_author = {$this->author} - AND post_name LIKE 'fifu-category%' + $sql = $this->wpdb->prepare(+ "SELECT GROUP_CONCAT(p.ID) AS ids+ FROM {$this->posts} p+ WHERE p.post_parent = %d+ AND p.post_author = %d+ AND p.post_name LIKE %s AND NOT EXISTS (- SELECT 1- FROM {$this->termmeta}- WHERE term_id = post_parent- AND meta_key = 'thumbnail_id'- AND meta_value = id- )- GROUP BY post_parent- ");- return $result ? $result[0]->ids : null;+ SELECT 1+ FROM {$this->termmeta} tm+ WHERE tm.term_id = p.post_parent+ AND tm.meta_key = 'thumbnail_id'+ AND tm.meta_value = p.ID+ )",+ (int) $term_id,+ (int) $this->author,+ 'fifu-category%' // pass pattern as a value; no %% needed+ );++ $ids_csv = $this->wpdb->get_var($sql);+ return $ids_csv ?: null; } function get_posts_without_featured_image($post_types) {+ $safe = $this->sanitize_post_types_list($post_types); return $this->wpdb->get_results(" SELECT id, post_title FROM {$this->posts} - WHERE post_type IN ('$post_types')+ WHERE post_type IN ($safe) AND post_status = 'publish' AND NOT EXISTS ( SELECT 1@@ -334,12 +470,14 @@ } function get_featured_and_gallery_ids($post_id) {- return $this->wpdb->get_results("- SELECT GROUP_CONCAT(meta_value SEPARATOR ',') as 'ids'+ $sql = $this->wpdb->prepare(+ "SELECT GROUP_CONCAT(meta_value SEPARATOR ',') as 'ids' FROM {$this->postmeta}- WHERE post_id = {$post_id}- AND meta_key IN ('_thumbnail_id')- ");+ WHERE post_id = %d+ AND meta_key IN ('_thumbnail_id')",+ (int) $post_id+ );+ return $this->wpdb->get_results($sql); } function insert_default_thumbnail_id($value) {@@ -352,25 +490,24 @@ // clean metadata function delete_attachments($ids) {- $this->wpdb->query("- DELETE FROM {$this->posts} - WHERE id IN ({$ids})- AND post_author = {$this->author}- ");+ $ids_csv = $this->sanitize_ids_csv($ids);+ $sql = $this->wpdb->prepare(+ "DELETE FROM {$this->posts} WHERE id IN ({$ids_csv}) AND post_author = %d",+ $this->author+ );+ $this->wpdb->query($sql); } function delete_attachment_meta_url_and_alt($ids) {- $this->wpdb->query("- DELETE FROM {$this->postmeta} + $ids_csv = $this->sanitize_ids_csv($ids);+ $sql = $this->wpdb->prepare(+ "DELETE FROM {$this->postmeta} WHERE meta_key IN ('_wp_attached_file', '_wp_attachment_image_alt', '_wp_attachment_metadata')- AND post_id IN ({$ids})- AND EXISTS (- SELECT 1 - FROM {$this->posts} - WHERE id = post_id - AND post_author = {$this->author}- )- ");+ AND post_id IN ({$ids_csv})+ AND EXISTS (SELECT 1 FROM {$this->posts} WHERE id = post_id AND post_author = %d)",+ $this->author+ );+ $this->wpdb->query($sql); } function delete_empty_urls_category() {@@ -398,40 +535,62 @@ /* wp_options */ function select_option_prefix($prefix) {- return $this->wpdb->get_results("- SELECT option_name, option_value+ if ($prefix === '')+ return []; // avoid SELECT all+ $like = $this->wpdb->esc_like($prefix) . '%'; // escape LIKE wildcards safely+ $sql = $this->wpdb->prepare(+ "SELECT option_name, option_value FROM {$this->options}- WHERE option_name LIKE '{$prefix}%'- ORDER BY option_name- ");+ WHERE option_name LIKE %s+ ORDER BY option_name",+ $like+ );+ return $this->wpdb->get_results($sql); } function delete_option_prefix($prefix) {- $this->wpdb->query("- DELETE- FROM {$this->options}- WHERE option_name LIKE '{$prefix}%'- ");+ if ($prefix === '') {+ return 0; // safety: avoid deleting everything+ }+ $like = $this->wpdb->esc_like($prefix) . '%'; // escape % and _+ $sql_select = $this->wpdb->prepare(+ "SELECT option_name FROM {$this->options} WHERE option_name LIKE %s",+ $like+ );+ $options_to_delete = $this->wpdb->get_col($sql_select);+ $sql_delete = $this->wpdb->prepare(+ "DELETE FROM {$this->options} WHERE option_name LIKE %s",+ $like+ );+ $deleted_count = (int) $this->wpdb->query($sql_delete);+ // Clear cache for deleted options+ foreach ($options_to_delete as $option_name) {+ wp_cache_delete($option_name, 'options');+ }+ return $deleted_count; } /* speed up */ function get_all_urls($page, $type, $keyword) {+ $page = max(0, (int) $page); // Ensure page is non-negative $start = $page * 1000; - $filter = "";+ // Posts filter+ $filter_posts = ''; if ($keyword) {+ $like = '%' . $this->wpdb->esc_like($keyword) . '%'; if ($type == 'title')- $filter = "AND p.post_title LIKE '%{$keyword}%'";+ $filter_posts = $this->wpdb->prepare('AND p.post_title LIKE %s', $like); elseif ($type == 'url')- $filter = "AND pm.meta_value LIKE '%{$keyword}%'";+ $filter_posts = $this->wpdb->prepare('AND pm.meta_value LIKE %s', $like); } $sql = " ( SELECT pm.meta_id, pm.post_id, pm.meta_value AS url, pm.meta_key, p.post_name, p.post_title, p.post_date, false AS category, null AS video_url FROM {$this->postmeta} pm- INNER JOIN {$this->posts} p ON pm.post_id = p.id {$filter}+ INNER JOIN {$this->posts} p ON pm.post_id = p.id {$filter_posts} WHERE pm.meta_key = 'fifu_image_url' AND pm.meta_value NOT LIKE '%https://cdn.fifu.app/%' AND pm.meta_value NOT LIKE 'http://localhost/%'@@ -439,19 +598,21 @@ ) "; if (class_exists('WooCommerce')) {- $filter = "";+ // Terms filter+ $filter_terms = ''; if ($keyword) {+ $like = '%' . $this->wpdb->esc_like($keyword) . '%'; if ($type == 'title')- $filter = "AND t.name LIKE '%{$keyword}%'";+ $filter_terms = $this->wpdb->prepare('AND t.name LIKE %s', $like); elseif ($type == 'url')- $filter = "AND tm.meta_value LIKE '%{$keyword}%'";+ $filter_terms = $this->wpdb->prepare('AND tm.meta_value LIKE %s', $like); } $sql .= " UNION ( SELECT tm.meta_id, tm.term_id AS post_id, tm.meta_value AS url, tm.meta_key, null AS post_name, t.name AS post_title, null AS post_date, true AS category, null AS video_url FROM {$this->termmeta} tm- INNER JOIN {$this->terms} t ON tm.term_id = t.term_id {$filter}+ INNER JOIN {$this->terms} t ON tm.term_id = t.term_id {$filter_terms} WHERE tm.meta_key IN ('fifu_image_url') AND tm.meta_value NOT LIKE '%https://cdn.fifu.app/%' AND tm.meta_value NOT LIKE 'http://localhost/%'@@ -494,16 +655,22 @@ } function get_posts_with_internal_featured_image($page, $type, $keyword) {- $start = $page * 1000;+ $start = max(0, (int) $page) * 1000; $filter = ""; if ($keyword) {- if ($type == 'title')- $filter = "AND p.post_title LIKE '%{$keyword}%'";- elseif ($type == 'postid')- $filter = "AND pm.post_id = {$keyword}";+ if ($type == 'title') {+ $like = '%' . $this->wpdb->esc_like($keyword) . '%';+ $filter = $this->wpdb->prepare('AND p.post_title LIKE %s', $like);+ } elseif ($type == 'postid') {+ $filter = $this->wpdb->prepare('AND pm.post_id = %d', (int) $keyword);+ } } + // Prepare author filter fragments once to avoid preparing the whole query later+ $author_clause_posts = $this->wpdb->prepare('AND att.post_author <> %d', $this->author);+ $author_clause_terms = $author_clause_posts;+ $sql = " ( SELECT @@ -520,7 +687,7 @@ INNER JOIN {$this->posts} att ON ( pm.meta_key = '_thumbnail_id' AND pm.meta_value = att.id- AND att.post_author <> {$this->author}+ {$author_clause_posts} ) WHERE NOT EXISTS ( SELECT 1@@ -540,10 +707,12 @@ if (class_exists('WooCommerce')) { $filter = ""; if ($keyword) {- if ($type == 'title')- $filter = "AND t.name LIKE '%{$keyword}%'";- elseif ($type == 'postid')- $filter = "AND tm.term_id = {$keyword}";+ if ($type == 'title') {+ $like = '%' . $this->wpdb->esc_like($keyword) . '%';+ $filter = $this->wpdb->prepare('AND t.name LIKE %s', $like);+ } elseif ($type == 'postid') {+ $filter = $this->wpdb->prepare('AND tm.term_id = %d', (int) $keyword);+ } } $sql .= " UNION @@ -562,7 +731,7 @@ INNER JOIN {$this->posts} att ON ( tm.meta_key = 'thumbnail_id' AND tm.meta_value = att.id- AND att.post_author <> {$this->author}+ {$author_clause_terms} ) WHERE NOT EXISTS ( SELECT 1@@ -581,12 +750,23 @@ } function get_posts_su($storage_ids) {- if ($storage_ids) {- $storage_ids = '"' . implode('","', $storage_ids) . '"';- $filter_post_image = "AND SUBSTRING_INDEX(SUBSTRING_INDEX(pm.meta_value, '/', 5), '/', -1) IN ({$storage_ids})";- $filter_term_image = "AND SUBSTRING_INDEX(SUBSTRING_INDEX(tm.meta_value, '/', 5), '/', -1) IN ({$storage_ids})";- } else+ if (!empty($storage_ids)) {+ // normalize and drop empties+ $ids = array_values(array_filter(array_map('strval', (array) $storage_ids), static fn($v) => $v !== ''));+ if ($ids) {+ $in = implode(',', array_fill(0, count($ids), '%s'));+ $filter_post_image = $this->wpdb->prepare(+ "AND SUBSTRING_INDEX(SUBSTRING_INDEX(pm.meta_value, '/', 5), '/', -1) IN ($in)", $ids+ );+ $filter_term_image = $this->wpdb->prepare(+ "AND SUBSTRING_INDEX(SUBSTRING_INDEX(tm.meta_value, '/', 5), '/', -1) IN ($in)", $ids+ );+ } else {+ $filter_post_image = $filter_term_image = "";+ }+ } else { $filter_post_image = $filter_term_image = "";+ } $sql = " (@@ -600,17 +780,17 @@ FROM {$this->postmeta} pm INNER JOIN {$this->posts} p ON pm.post_id = p.id WHERE pm.meta_key LIKE 'fifu_%image_url%'- AND pm.meta_value LIKE 'https://cdn.fifu.app/%'" .- $filter_post_image . "+ AND pm.meta_value LIKE 'https://cdn.fifu.app/%'+ {$filter_post_image} ) "; if (class_exists('WooCommerce')) {- $sql .= " + $sql .= " UNION ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(tm.meta_value, '/', 5), '/', -1) AS storage_id, t.name AS post_title, - null AS post_date, + NULL AS post_date, tm.meta_id, tm.term_id AS post_id, tm.meta_key, @@ -618,11 +798,12 @@ FROM {$this->termmeta} tm INNER JOIN {$this->terms} t ON tm.term_id = t.term_id WHERE tm.meta_key = 'fifu_image_url'- AND tm.meta_value LIKE 'https://cdn.fifu.app/%'" .- $filter_term_image . "+ AND tm.meta_value LIKE 'https://cdn.fifu.app/%'+ {$filter_term_image} ) "; }+ return $this->wpdb->get_results($sql); } @@ -678,26 +859,35 @@ function speed_up_custom_fields($bucket_id, $thumbnails, $is_ctgr) { $table = $is_ctgr ? $this->termmeta : $this->postmeta; - $query = "- INSERT INTO {$table} (meta_id, meta_value) VALUES ";- $count = 0;+ $values = [];+ $args = [];+ foreach ($thumbnails as $thumbnail) { $su_url = $this->get_su_url($bucket_id, $thumbnail->storage_id); - if ($count++ != 0)- $query .= ", ";- $query .= "({$thumbnail->meta_id},'{$su_url}') ";+ $values[] = '(%d,%s)';+ $args[] = (int) $thumbnail->meta_id;+ $args[] = $su_url; }- $query .= "ON DUPLICATE KEY UPDATE meta_value=VALUES(meta_value)";- return $this->wpdb->get_results($query);++ if (!$values)+ return 0;++ $query = "+ INSERT INTO {$table} (meta_id, meta_value)+ VALUES " . implode(', ', $values) . "+ ON DUPLICATE KEY UPDATE meta_value = VALUES(meta_value)+ ";++ return $this->wpdb->query($this->wpdb->prepare($query, $args)); } function get_thumbnail_ids($thumbnails, $is_ctgr) {- // join post_ids- $i = 0;- $ids = null;+ // join post_ids (sanitized)+ $ids_list = array(); foreach ($thumbnails as $thumbnail)- $ids = ($i++ == 0) ? $thumbnail->post_id : ($ids . "," . $thumbnail->post_id);+ $ids_list[] = (int) $thumbnail->post_id;+ $ids = $this->sanitize_ids_csv($ids_list); // get featured ids if ($is_ctgr) {@@ -745,45 +935,57 @@ if ($count++ != 0) $query .= ", ";- $query .= "(" . $att_ids_map[$thumbnail->meta_id] . ",'{$su_url}') ";+ $query .= $this->wpdb->prepare("(%d, %s)", $att_ids_map[$thumbnail->meta_id], $su_url) . " "; } $query .= "ON DUPLICATE KEY UPDATE post_content_filtered=VALUES(post_content_filtered)"; return $this->wpdb->get_results($query); } function get_thumbnail_meta_ids($thumbnails, $att_ids_map) {- // join post_ids- $i = 0;- $ids = null;+ // Collect distinct numeric attachment post_ids+ $ids_arr = array(); foreach ($thumbnails as $thumbnail) { if (!isset($att_ids_map[$thumbnail->meta_id])) // no metadata, only custom field continue;- $ids = ($i++ == 0) ? $att_ids_map[$thumbnail->meta_id] : ($ids . "," . $att_ids_map[$thumbnail->meta_id]);+ $ids_arr[] = (int) $att_ids_map[$thumbnail->meta_id]; }+ $ids_arr = array_values(array_unique(array_filter($ids_arr, function ($v) {+ return $v > 0;+ }))); - // get meta ids- $result = $this->wpdb->get_results("+ // No IDs -> nothing to query+ if (empty($ids_arr)) {+ return array();+ }++ // Build prepared IN(...) and run the safe query+ $placeholders = implode(',', array_fill(0, count($ids_arr), '%d'));+ $sql = " SELECT meta_id, post_id- FROM {$this->postmeta} - WHERE post_id IN ({$ids}) - AND meta_key = '_wp_attached_file'- ");+ FROM {$this->postmeta}+ WHERE post_id IN ($placeholders)+ AND meta_key = %s+ ";+ $params = array_merge($ids_arr, array('_wp_attached_file'));+ $result = $this->wpdb->get_results($this->wpdb->prepare($sql, $params)); // map att_id -> meta_id $attid_metaid_map = array();- foreach ($result as $res)+ foreach ($result as $res) { $attid_metaid_map[$res->post_id] = $res->meta_id;+ } - // map meta_id (fifu metadata) -> meta_id (atachment metadata)+ // map meta_id (fifu metadata) -> meta_id (attachment metadata) $map = array(); foreach ($thumbnails as $thumbnail) { if (!isset($att_ids_map[$thumbnail->meta_id])) // no metadata, only custom field continue;- if (!isset($attid_metaid_map[$att_ids_map[$thumbnail->meta_id]])) // no metadata, only custom field+ $att_id = (int) $att_ids_map[$thumbnail->meta_id];+ if (!isset($attid_metaid_map[$att_id])) // no attachment metadata continue;- $att_meta_id = $attid_metaid_map[$att_ids_map[$thumbnail->meta_id]];- $map[$thumbnail->meta_id] = $att_meta_id;+ $map[$thumbnail->meta_id] = $attid_metaid_map[$att_id]; }+ return $map; } @@ -791,6 +993,7 @@ $count = 0; $query = " INSERT INTO {$this->postmeta} (meta_id, meta_value) VALUES ";+ foreach ($thumbnails as $thumbnail) { if (!isset($meta_ids_map[$thumbnail->meta_id])) // no metadata, only custom field continue;@@ -799,8 +1002,11 @@ if ($count++ != 0) $query .= ", ";- $query .= "(" . $meta_ids_map[$thumbnail->meta_id] . ",'{$su_url}') ";++ // Minimal change: use prepare to safely build each VALUES tuple+ $query .= $this->wpdb->prepare("(%d, %s)", $meta_ids_map[$thumbnail->meta_id], $su_url) . " "; }+ $query .= "ON DUPLICATE KEY UPDATE meta_value=VALUES(meta_value)"; return $this->wpdb->get_results($query); }@@ -907,30 +1113,61 @@ function revert_custom_fields($thumbnails, $urls, $video_urls, $is_ctgr) { $table = $is_ctgr ? $this->termmeta : $this->postmeta; + // Return early if no thumbnails to process+ if (empty($thumbnails)) {+ return null;+ }+ $query = " INSERT INTO {$table} (meta_id, meta_value) VALUES "; $count = 0;+ foreach ($thumbnails as $thumbnail) {- if ($count++ != 0)+ if ($count++ != 0) { $query .= ", ";- $url = $urls[$thumbnail->storage_id];- $query .= "({$thumbnail->meta_id},'{$url}')";+ }++ $url = (isset($urls[$thumbnail->storage_id]) ? $urls[$thumbnail->storage_id] : '');++ // Minimal change: build each VALUES tuple with prepare to avoid SQL injection+ $query .= $this->wpdb->prepare("(%d, %s)", (int) $thumbnail->meta_id, $url); }- $query .= "ON DUPLICATE KEY UPDATE meta_value=VALUES(meta_value)";++ $query .= " ON DUPLICATE KEY UPDATE meta_value=VALUES(meta_value)"; return $this->wpdb->get_results($query); } function revert_attachments($urls, $thumbnails, $att_ids_map) {+ // Handle null or invalid parameters+ if ($urls === null || !is_array($urls))+ $urls = [];+ if ($thumbnails === null || !is_array($thumbnails))+ $thumbnails = [];+ if ($att_ids_map === null || !is_array($att_ids_map))+ $att_ids_map = [];+ $count = 0; $query = " INSERT INTO {$this->posts} (id, post_content_filtered) VALUES ";+ foreach ($thumbnails as $thumbnail) { if (!isset($att_ids_map[$thumbnail->meta_id])) // no metadata, only custom field continue;+ if ($count++ != 0) $query .= ", ";- $query .= "(" . $att_ids_map[$thumbnail->meta_id] . ",'" . $urls[$thumbnail->storage_id] . "')";++ $url = isset($urls[$thumbnail->storage_id]) ? $urls[$thumbnail->storage_id] : '';++ // Minimal change: use prepare to safely build each VALUES tuple+ $query .= $this->wpdb->prepare("(%d, %s)", (int) $att_ids_map[$thumbnail->meta_id], $url); }++ // If no thumbnails were processed, return early+ if ($count == 0) {+ return array(); // Return empty array instead of running invalid query+ }+ $query .= "ON DUPLICATE KEY UPDATE post_content_filtered=VALUES(post_content_filtered)"; return $this->wpdb->get_results($query); }@@ -939,15 +1176,28 @@ $count = 0; $query = " INSERT INTO {$this->postmeta} (meta_id, meta_value) VALUES ";+ foreach ($thumbnails as $thumbnail) { if (!isset($meta_ids_map[$thumbnail->meta_id])) // no metadata, only custom field continue;+ if ($count++ != 0)
Vulnerability Existed: yes SQL Injection - CWE-89 - admin/db.php [44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300, 2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325,
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/admin/debug.php 2025-11-19 10:52:43.033414340 +0000+++ cache/featured-image-from-url_5.2.8/admin/debug.php 2025-11-19 10:52:44.548511457 +0000@@ -28,6 +28,44 @@ return new WP_REST_Response($metaout, 200); } +function fifu_api_debug_log(WP_REST_Request $request) {+ $type = $request->get_param('type') ?? 'plugin';+ $lines = intval($request->get_param('lines') ?? 200);+ if ($lines <= 0) {+ $lines = 200;+ }+ if ($lines > 5000) { // hard cap to avoid huge responses+ $lines = 5000;+ }++ $upload_dir = wp_upload_dir();+ $basedir = $upload_dir['basedir'] ?? '';+ $filename = $type === 'cloud' ? 'fifu-cloud.log' : 'fifu-plugin.log';+ $path = $basedir ? (rtrim($basedir, '/\\') . '/' . $filename) : '';++ if (!$path || !file_exists($path)) {+ return new WP_REST_Response('Log file not found', 404);+ }++ // Ensure readable for this request+ @chmod($path, 0600);+ $content = @file_get_contents($path);+ // Preserve permission according to current toggle+ $debug_on = function_exists('fifu_is_on') ? fifu_is_on('fifu_debug') : false;+ @chmod($path, $debug_on ? 0600 : 0200);+ if ($content === false) {+ return new WP_REST_Response('Unable to read log file', 403);+ }++ $parts = preg_split('/\r?\n/', rtrim($content, "\r\n"));+ $slice = array_slice($parts, -$lines);+ $text = implode("\n", $slice) . "\n";++ $response = new WP_REST_Response($text, 200);+ $response->header('Content-Type', 'text/plain; charset=' . get_option('blog_charset'));+ return $response;+}+ add_action('rest_api_init', function () { register_rest_route('featured-image-from-url/v2', '/debug-slug/(?P<slug>[a-z0-9-_]+)', array( 'methods' => 'GET',@@ -88,4 +126,25 @@ return fifu_is_on('fifu_debug'); }, ));-});+ register_rest_route('featured-image-from-url/v2', '/debug-log/(?P<type>(cloud|plugin))', array(+ 'methods' => 'GET',+ 'callback' => 'fifu_api_debug_log',+ 'permission_callback' => function ($request) {+ return fifu_is_on('fifu_debug');+ },+ 'args' => array(+ 'type' => array(+ 'required' => true,+ 'validate_callback' => function ($param) {+ return in_array($param, array('cloud', 'plugin'), true);+ }+ ),+ 'lines' => array(+ 'required' => false,+ 'validate_callback' => function ($param) {+ return is_numeric($param) && intval($param) > 0; // capped inside handler+ }+ ),+ ),+ ));+});\ No newline at end of file
Vulnerability Existed: no
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') - admin/debug.php 31-57
Old Code:
```php
function fifu_api_debug_log(WP_REST_Request $request) {
$type = $request->get_param('type') ?? 'plugin';
$lines = intval($request->get_param('lines') ?? 200);
if ($lines <= 0) {
$lines = 200;
}
if ($lines > 5000) { // hard cap to avoid huge responses
$lines = 5000;
}
$upload_dir = wp_upload_dir();
$basedir = $upload_dir['basedir'] ?? '';
$filename = $type === 'cloud' ? 'fifu-cloud.log' : 'fifu-plugin.log';
$path = $basedir ? (rtrim($basedir, '/\\') . '/' . $filename) : '';
if (!$path || !file_exists($path)) {
return new WP_REST_Response('Log file not found', 404);
}
// Ensure readable for this request
@chmod($path, 0600);
$content = @file_get_contents($path);
// Preserve permission according to current toggle
$debug_on = function_exists('fifu_is_on') ? fifu_is_on('fifu_debug') : false;
@chmod($path, $debug_on ? 0600 : 0200);
if ($content === false) {
return new WP_REST_Response('Unable to read log file', 403);
}
$parts = preg_split('/\r?\n/', rtrim($content, "\r\n"));
$slice = array_slice($parts, -$lines);
$text = implode("\n", $slice) . "\n";
$response = new WP_REST_Response($text, 200);
$response->header('Content-Type', 'text/plain; charset=' . get_option('blog_charset'));
return $response;
}
```
Fixed Code:
```php
function fifu_api_debug_log(WP_REST_Request $request) {
$type = $request->get_param('type') ?? 'plugin';
$lines = intval($request->get_param('lines') ?? 200);
if ($lines <= 0) {
$lines = 200;
}
if ($lines > 5000) { // hard cap to avoid huge responses
$lines = 5000;
}
$upload_dir = wp_upload_dir();
$basedir = $upload_dir['basedir'] ?? '';
$filename = $type === 'cloud' ? 'fifu-cloud.log' : 'fifu-plugin.log';
$path = $basedir ? (rtrim($basedir, '/\\') . '/' . $filename) : '';
if (!$path || !file_exists($path)) {
return new WP_REST_Response('Log file not found', 404);
}
// Ensure readable for this request
@chmod($path, 0600);
$content = @file_get_contents($path);
// Preserve permission according to current toggle
$debug_on = function_exists('fifu_is_on') ? fifu_is_on('fifu_debug') : false;
@chmod($path, $debug_on ? 0600 : 0200);
if ($content === false) {
return new WP_REST_Response('Unable to read log file', 403);
}
$parts = preg_split('/\r?\n/', rtrim($content, "\r\n"));
$slice = array_slice($parts, -$lines);
$text = implode("\n", $slice) . "\n";
$response = new WP_REST_Response($text, 200);
$response->header('Content-Type', 'text/plain; charset=' . get_option('blog_charset'));
return $response;
}
```
Explanation:
The user input `$type` parameter is strictly validated by the REST route's `validate_callback` to only accept 'cloud' or 'plugin' values. The filename is hardcoded based on this validated input - either 'fifu-cloud.log' or 'fifu-plugin.log'. The path is constructed using WordPress's `wp_upload_dir()` function and concatenated with the hardcoded filename. There is no path traversal vulnerability because the filename is not derived from user input without validation, and the `$type` parameter is restricted to two specific values that map to predetermined log file names.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/admin/log.php 2025-11-19 10:52:43.036414532 +0000+++ cache/featured-image-from-url_5.2.8/admin/log.php 2025-11-19 10:52:44.555511906 +0000@@ -12,17 +12,52 @@ $upload_dir = wp_upload_dir()['basedir'] ?? ''; $filepath = "{$upload_dir}/{$file}.log"; - // Remove the file- if (file_exists($filepath) && filesize($filepath) > 10 * 1024 * 1024)- unlink($filepath);+ // Rotate the .log file if it exceeds 10MB+ if (file_exists($filepath) && filesize($filepath) > 10 * 1024 * 1024) {+ @unlink($filepath);+ } - if (is_array($entry))+ if (is_array($entry)) { $entry = json_encode([current_time('mysql') => $entry], JSON_UNESCAPED_SLASHES);+ } - $file = fopen($filepath, $mode);- $bytes = fwrite($file, "{$entry}\n");- fclose($file);+ // Ensure file exists before adjusting permissions+ if (!file_exists($filepath)) {+ @touch($filepath);+ }++ // Set permissions based on current debug toggle+ $debug_on = function_exists('fifu_is_on') ? fifu_is_on('fifu_debug') : false;+ @chmod($filepath, $debug_on ? 0600 : 0200);++ $fh = fopen($filepath, $mode);+ $bytes = fwrite($fh, "{$entry}\n");+ fclose($fh); return $bytes; } +// Immediately adjust log file permissions when fifu_debug changes+function fifu_set_log_permissions($debug_on) {+ $upload_dir = wp_upload_dir()['basedir'] ?? '';+ if (!$upload_dir)+ return;+ $files = [+ $upload_dir . '/fifu-plugin.log',+ $upload_dir . '/fifu-cloud.log',+ ];+ $perm = $debug_on ? 0600 : 0200;+ foreach ($files as $file) {+ if (file_exists($file)) {+ @chmod($file, $perm);+ }+ }+}++add_action('updated_option', function ($option, $old_value, $value) {+ if ($option === 'fifu_debug') {+ fifu_set_log_permissions($value === 'toggleon');+ }+}, 10, 3);++
Vulnerability Existed: no
CWE-732: Incorrect Permission Assignment for Critical Resource - admin/log.php [28, 45]
Old Code:
// Set permissions based on current debug toggle
$debug_on = function_exists('fifu_is_on') ? fifu_is_on('fifu_debug') : false;
@chmod($filepath, $debug_on ? 0600 : 0200);
$fh = fopen($filepath, $mode);
$bytes = fwrite($fh, "{$entry}\n");
fclose($fh);
return $bytes;
}
// Immediately adjust log file permissions when fifu_debug changes
function fifu_set_log_permissions($debug_on) {
$upload_dir = wp_upload_dir()['basedir'] ?? '';
if (!$upload_dir)
return;
$files = [
$upload_dir . '/fifu-plugin.log',
$upload_dir . '/fifu-cloud.log',
];
$perm = $debug_on ? 0600 : 0200;
foreach ($files as $file) {
if (file_exists($file)) {
@chmod($file, $perm);
}
}
}
add_action('updated_option', function ($option, $old_value, $value) {
if ($option === 'fifu_debug') {
fifu_set_log_permissions($value === 'toggleon');
}
}, 10, 3);
Fixed Code:
No changes needed
Explanation:
The code implements proper file permission management. When debug mode is enabled (fifu_debug = 'toggleon'), log files are set to 0600 (read/write for owner only). When debug mode is disabled, permissions are set to 0200 (write-only for owner). Both permission modes prevent unauthorized access - 0600 prevents other users from reading/writing, and 0200 prevents all reading access while maintaining write capability for the owner. The permissions are properly managed both during log writing and when the debug option changes via the WordPress hook.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/admin/menu.php 2025-11-19 10:52:43.036414532 +0000+++ cache/featured-image-from-url_5.2.8/admin/menu.php 2025-11-19 10:52:44.555511906 +0000@@ -161,6 +161,9 @@ wp_enqueue_style('fifu-base-ui-css', plugins_url('/html/css/base-ui.css', __FILE__), array(), fifu_version_number_enq()); wp_enqueue_style('fifu-menu-css', plugins_url('/html/css/menu.css', __FILE__), array(), fifu_version_number_enq()); + // page-specific JS to hide admin notices, matching other FIFU pages + wp_enqueue_script('fifu-support-data-js', plugins_url('/html/js/support-data.js', __FILE__), array('jquery', 'jquery-ui'), fifu_version_number_enq()); + $skip = esc_attr(get_option('fifu_skip')); $html_cpt = esc_attr(get_option('fifu_html_cpt')); $square_mobile = esc_attr(get_option('fifu_square_mobile'));
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - admin/menu.php [164]
Old Code:
wp_enqueue_script('fifu-support-data-js', plugins_url('/html/js/support-data.js', __FILE__), array('jquery', 'jquery-ui'), fifu_version_number_enq());
Fixed Code:
wp_enqueue_script('fifu-support-data-js', plugins_url('/html/js/support-data.js', __FILE__), array('jquery', 'jquery-ui'), fifu_version_number_enq());
Explanation:
The added code uses wp_enqueue_script() to safely register and enqueue a JavaScript file. This is a WordPress core function that properly handles script URLs and dependencies. The plugins_url() function generates a safe, validated URL path to the plugin's JavaScript file. There is no user input involved in this operation - all parameters are hardcoded strings or function calls that return version numbers. The script path is constructed from the plugin directory and fixed file path '/html/js/support-data.js', making it impossible for attackers to control the script source.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/featured-image-from-url.php 2025-11-19 10:52:43.038414660 +0000+++ cache/featured-image-from-url_5.2.8/featured-image-from-url.php 2025-11-19 10:52:44.558512098 +0000@@ -4,7 +4,7 @@ * Plugin Name: Featured Image from URL (FIFU) * Plugin URI: https://fifu.app/ * Description: Use remote media as the featured image and beyond. - * Version: 5.2.7 + * Version: 5.2.8 * Author: fifu.app * Author URI: https://fifu.app/ * WC requires at least: 4.0 @@ -20,9 +20,12 @@ define('FIFU_ELEMENTOR_DIR', FIFU_PLUGIN_DIR . 'elementor'); define('FIFU_GRAVITY_DIR', FIFU_PLUGIN_DIR . 'gravity-forms'); define('FIFU_LANGUAGES_DIR', WP_CONTENT_DIR . '/uploads/fifu/languages/'); -define('FIFU_DELETE_ALL_URLS', false); define('FIFU_CLOUD_DEBUG', false); +if (!defined('FIFU_DELETE_ALL_URLS')) { + define('FIFU_DELETE_ALL_URLS', false); +} + $FIFU_SESSION = array(); // Required includes with error handling
Vulnerability Existed: no
CWE-798: Use of Hard-coded Credentials - CWE-798 - featured-image-from-url.php [20]
Old Code:
`define('FIFU_DELETE_ALL_URLS', false);`
Fixed Code:
`if (!defined('FIFU_DELETE_ALL_URLS')) {
define('FIFU_DELETE_ALL_URLS', false);
}`
Explanation:
The change modifies how the FIFU_DELETE_ALL_URLS constant is defined. Previously it was hardcoded to false. Now it checks if the constant is already defined before setting it to false. This is not a security vulnerability fix but rather an improvement to allow the constant to be overridden elsewhere. There is no user input involved, no taint flow, and no security sink. The change provides more flexibility in configuration but does not address any security vulnerability.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/includes/attachment.php 2025-11-19 10:52:43.038414660 +0000+++ cache/featured-image-from-url_5.2.8/includes/attachment.php 2025-11-19 10:52:44.559512162 +0000@@ -63,14 +63,14 @@ function fifu_query_attachments($where) { global $wpdb; if (fifu_is_web_story() || (($_POST['action'] ?? '') == 'query-attachments' || ($_POST['action'] ?? '') == 'get-attachment'))- $where .= ' AND ' . $wpdb->prefix . 'posts.post_author <> ' . FIFU_AUTHOR . ' ';+ $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author <> %d ", FIFU_AUTHOR); return $where; } add_filter('posts_where', function ($where, \WP_Query $q) { global $wpdb; if (fifu_is_web_story() || (is_admin() && $q->is_main_query() && strpos($where, 'attachment') !== false))- $where .= ' AND ' . $wpdb->prefix . 'posts.post_author <> ' . FIFU_AUTHOR . ' ';+ $where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author <> %d ", FIFU_AUTHOR); return $where; }, 10, 2);
Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - includes/attachment.php [63-63]
Old Code:
$where .= ' AND ' . $wpdb->prefix . 'posts.post_author <> ' . FIFU_AUTHOR . ' ';
Fixed Code:
$where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author <> %d ", FIFU_AUTHOR);
Explanation:
The old code directly concatenates the FIFU_AUTHOR constant into the SQL query string without proper parameterization. While FIFU_AUTHOR appears to be a constant, the code structure shows it's being treated as a variable value that gets embedded directly into SQL. The fix uses $wpdb->prepare with %d placeholder, which properly parameterizes the value and prevents SQL injection. The vulnerability existed because user input could potentially influence the query construction through the $_POST['action'] condition, and the direct string concatenation created a SQL injection vector.
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - includes/attachment.php [70-70]
Old Code:
$where .= ' AND ' . $wpdb->prefix . 'posts.post_author <> ' . FIFU_AUTHOR . ' ';
Fixed Code:
$where .= $wpdb->prepare(" AND {$wpdb->posts}.post_author <> %d ", FIFU_AUTHOR);
Explanation:
The old code directly concatenates the FIFU_AUTHOR constant into the SQL query string without proper parameterization in the posts_where filter. Similar to the first instance, this creates a SQL injection vulnerability by embedding values directly into the SQL string. The fix properly parameterizes the value using $wpdb->prepare with %d placeholder, which binds the value as a parameter and prevents SQL injection attacks.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/includes/speedup.php 2025-11-19 10:52:43.039414724 +0000+++ cache/featured-image-from-url_5.2.8/includes/speedup.php 2025-11-19 10:52:44.560512227 +0000@@ -189,9 +189,11 @@ function fifu_speedup_fix_size($width, $height) { $sizes = unserialize(FIFU_SPEEDUP_SIZES); - // Check if the width is present in the available sizes+ // Preserve original width for aspect ratio calculation+ $original_width = $width;++ // Snap width to the next allowed size if needed if (!in_array($width, $sizes)) {- // Look for the next higher value foreach ($sizes as $size) { if ($size >= $width) { $width = $size;@@ -199,18 +201,18 @@ } } - // If the next higher value is bigger than 1920, use 1920+ // Hard cap at 1920 if ($width > 1920) { $width = 1920; } } - // Calculate the new height to maintain the aspect ratio+ // Recalculate height to preserve original aspect ratio if ($height) {- $aspect_ratio = $height / $width;- $new_height = $width * $aspect_ratio;+ $aspect_ratio = $height / max(1, $original_width);+ $new_height = (int) round($width * $aspect_ratio); } else {- $new_height = $height;+ $new_height = $height; // keep as is (0 or null) } return array($width, $new_height);
Vulnerability Existed: no
Improper Check for Unusual or Exceptional Conditions - CWE-754 - includes/speedup.php 189-223
Old Code:
```php
function fifu_speedup_fix_size($width, $height) {
$sizes = unserialize(FIFU_SPEEDUP_SIZES);
// Check if the width is present in the available sizes
if (!in_array($width, $sizes)) {
// Look for the next higher value
foreach ($sizes as $size) {
if ($size >= $width) {
$width = $size;
break;
}
}
// If the next higher value is bigger than 1920, use 1920
if ($width > 1920) {
$width = 1920;
}
}
// Calculate the new height to maintain the aspect ratio
if ($height) {
$aspect_ratio = $height / $width;
$new_height = $width * $aspect_ratio;
} else {
$new_height = $height;
}
return array($width, $new_height);
```
Fixed Code:
```php
function fifu_speedup_fix_size($width, $height) {
$sizes = unserialize(FIFU_SPEEDUP_SIZES);
// Preserve original width for aspect ratio calculation
$original_width = $width;
// Snap width to the next allowed size if needed
if (!in_array($width, $sizes)) {
foreach ($sizes as $size) {
if ($size >= $width) {
$width = $size;
break;
}
}
// Hard cap at 1920
if ($width > 1920) {
$width = 1920;
}
}
// Recalculate height to preserve original aspect ratio
if ($height) {
$aspect_ratio = $height / max(1, $original_width);
$new_height = (int) round($width * $aspect_ratio);
} else {
$new_height = $height; // keep as is (0 or null)
}
return array($width, $new_height);
```
Explanation:
The code change addresses a potential division by zero vulnerability. In the old code, if `$width` was 0, the calculation `$height / $width` would cause division by zero. The fix uses `max(1, $original_width)` to ensure the divisor is at least 1, preventing division by zero. There is no user input flowing into this function that could be exploited for injection or other security vulnerabilities. The change is purely defensive programming to handle edge cases in image dimension calculations.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/featured-image-from-url_5.2.7/includes/util.php 2025-11-19 10:52:43.040414788 +0000+++ cache/featured-image-from-url_5.2.8/includes/util.php 2025-11-19 10:52:44.561512291 +0000@@ -288,6 +288,10 @@ return rtrim(strtr(base64_encode($url), '+/', '-_'), '='); } +function fifu_unit_test() {+ return 'Hello, World!';+}+ // developers function fifu_dev_set_image($post_id, $image_url) {
Vulnerability Existed: no
No vulnerability found - No CWE ID - includes/util.php 288-292
Old Code:
```php
function fifu_unit_test() {
return 'Hello, World!';
}
```
Fixed Code:
```php
function fifu_unit_test() {
return 'Hello, World!';
}
```
Explanation:
The added function fifu_unit_test() only returns a hardcoded string 'Hello, World!' and does not accept any user input parameters. There are no entry points for user-controlled data, no data transformations or validations to analyze, and no security-sensitive sinks present in this function. The function is completely self-contained with no external dependencies or input sources.
The Featured Image from URL (FIFU) plugin for WordPress is vulnerable to SQL Injection via the get_posts_with_internal_featured_image() function in all versions up to, and including, 5.2.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/pagbank-connect_4.44.3/rm-pagbank.php 2025-11-19 10:51:19.106035271 +0000+++ cache/pagbank-connect_4.44.4/rm-pagbank.php 2025-11-19 10:51:21.176167933 +0000@@ -11,7 +11,7 @@ * Plugin Name: PagBank Connect * Plugin URI: https://pbintegracoes.com * Description: Integra seu WooCommerce com as APIs PagSeguro v4 através da aplicação de Ricardo Martins (com descontos nas taxas oficiais), com suporte a PIX transparente e muito mais.- * Version: 4.44.3+ * Version: 4.44.4 * Requires at least: 5.2 * Tested up to: 6.8 * Requires PHP: 7.4@@ -33,7 +33,7 @@ defined( 'ABSPATH' ) || die( 'No direct script access allowed!' ); // Plugin constants.-define( 'WC_PAGSEGURO_CONNECT_VERSION', '4.44.3' );+define( 'WC_PAGSEGURO_CONNECT_VERSION', '4.44.4' ); define( 'WC_PAGSEGURO_CONNECT_PLUGIN_FILE', __FILE__ ); define( 'WC_PAGSEGURO_CONNECT_BASE_DIR', __DIR__ ); define( 'WC_PAGSEGURO_CONNECT_TEMPLATES_DIR', WC_PAGSEGURO_CONNECT_BASE_DIR . '/src/templates/' );
Vulnerability Existed: no No vulnerability - N/A - rm-pagbank.php [11,33] Old Code: * Version: 4.44.3 define( 'WC_PAGSEGURO_CONNECT_VERSION', '4.44.3' ); Fixed Code: * Version: 4.44.4 define( 'WC_PAGSEGURO_CONNECT_VERSION', '4.44.4' ); Explanation: The diff shows only version number updates from 4.44.3 to 4.44.4 in the plugin header comment and constant definition. These changes contain no user input, no data processing, no sinks, and no security-related functionality. Version number changes are routine maintenance updates with no security implications.
The PagBank / PagSeguro Connect para WooCommerce plugin for WordPress is vulnerable to SQL Injection via the 'status' parameter in all versions up to, and including, 4.44.3 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Shop Manager-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/pagbank-connect_4.44.3/src/Connect/Recurring/Admin/Subscriptions/SubscriptionList.php 2025-11-19 10:51:19.109035463 +0000+++ cache/pagbank-connect_4.44.4/src/Connect/Recurring/Admin/Subscriptions/SubscriptionList.php 2025-11-19 10:51:21.181168253 +0000@@ -90,14 +90,15 @@ $orderby = wp_unslash($orderby); $order = (isset($_GET['order']) && in_array($_GET['order'], array('asc', 'desc'))) ? $_GET['order'] : 'desc'; //phpcs:ignore WordPress.Security.NonceVerification + global $wpdb; $where = "1=1"; if (!empty($_REQUEST['status'])) { $status = sanitize_text_field(wp_unslash($_REQUEST['status']));- $where .= " AND status = '$status'";+ $where .= $wpdb->prepare(" AND status = %s", $status); } if (!empty($_REQUEST['order_id'])) { $order_id = intval($_REQUEST['order_id']);- $where .= " AND initial_order_id = $order_id";+ $where .= $wpdb->prepare(" AND initial_order_id = %d", $order_id); }
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - src/Connect/Recurring/Admin/Subscriptions/SubscriptionList.php [94-98]
Old Code:
```php
if (!empty($_REQUEST['status'])) {
$status = sanitize_text_field(wp_unslash($_REQUEST['status']));
$where .= " AND status = '$status'";
}
if (!empty($_REQUEST['order_id'])) {
$order_id = intval($_REQUEST['order_id']);
$where .= " AND initial_order_id = $order_id";
}
```
Fixed Code:
```php
global $wpdb;
if (!empty($_REQUEST['status'])) {
$status = sanitize_text_field(wp_unslash($_REQUEST['status']));
$where .= $wpdb->prepare(" AND status = %s", $status);
}
if (!empty($_REQUEST['order_id'])) {
$order_id = intval($_REQUEST['order_id']);
$where .= $wpdb->prepare(" AND initial_order_id = %d", $order_id);
}
```
Explanation:
The old code directly concatenates user input into SQL queries. For the 'status' parameter: $_REQUEST['status'] is user input → sanitize_text_field() only sanitizes for XSS, not SQL injection → value is directly inserted into SQL string with single quotes. For the 'order_id' parameter: $_REQUEST['order_id'] is user input → intval() converts to integer but the value is still directly concatenated into SQL. Both cases allow attacker-controlled values to reach the SQL sink unparameterized, enabling SQL injection. The fix uses $wpdb->prepare() with parameterized queries, which properly separates data from SQL structure.
The PagBank / PagSeguro Connect para WooCommerce plugin for WordPress is vulnerable to SQL Injection via the 'status' parameter in all versions up to, and including, 4.44.3 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Shop Manager-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/pagbank-connect_4.44.3/src/Connect/Recurring/RecurringDashboard.php 2025-11-19 10:51:19.110035527 +0000+++ cache/pagbank-connect_4.44.4/src/Connect/Recurring/RecurringDashboard.php 2025-11-19 10:51:21.182168318 +0000@@ -28,18 +28,26 @@ return $order->get_id(); }, $orders); - $ids_string_placeholders = implode(', ', array_fill(0, count($ids), '%d'));- global $wpdb;- //select from pagbank_recurring where initial order is one of those+ + // If no orders, return empty array+ if (empty($ids)) {+ return [];+ }+ + // Create placeholders for each ID+ $placeholders = array_fill(0, count($ids), '%d');+ $format = implode(',', $placeholders);+ + // Prepare and execute the query safely $table = $wpdb->prefix . 'pagbank_recurring';- $subscriptions = $wpdb->get_results(- $wpdb->prepare(- "SELECT * FROM `$table` WHERE initial_order_id IN ( $ids_string_placeholders ) ORDER BY id DESC",- $ids- )+ $query = $wpdb->prepare(+ "SELECT * FROM `$table` WHERE initial_order_id IN ($format) ORDER BY id DESC",+ $ids ); + $subscriptions = $wpdb->get_results($query);+ if ( ! empty($subscriptions)) { return $subscriptions;
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - src/Connect/Recurring/RecurringDashboard.php 28-40
Old Code:
```php
$ids_string_placeholders = implode(', ', array_fill(0, count($ids), '%d'));
global $wpdb;
//select from pagbank_recurring where initial order is one of those
$table = $wpdb->prefix . 'pagbank_recurring';
$subscriptions = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM `$table` WHERE initial_order_id IN ( $ids_string_placeholders ) ORDER BY id DESC",
$ids
)
);
```
Fixed Code:
```php
// If no orders, return empty array
if (empty($ids)) {
return [];
}
// Create placeholders for each ID
$placeholders = array_fill(0, count($ids), '%d');
$format = implode(',', $placeholders);
// Prepare and execute the query safely
$table = $wpdb->prefix . 'pagbank_recurring';
$query = $wpdb->prepare(
"SELECT * FROM `$table` WHERE initial_order_id IN ($format) ORDER BY id DESC",
$ids
);
$subscriptions = $wpdb->get_results($query);
```
Explanation:
The vulnerability existed because the original code used string concatenation to build the IN clause placeholders outside of $wpdb->prepare(). The $ids_string_placeholders variable contained a string like "%d, %d, %d" which was then concatenated into the SQL query string before being passed to $wpdb->prepare(). This meant the placeholders were treated as literal string content rather than parameter markers. The $ids array values were then passed to prepare(), but since the placeholders were already in the string, WordPress would treat the entire IN clause as a single parameter, potentially allowing SQL injection if an attacker could control the $ids values. The fix properly builds the format string and passes both the format and parameters to $wpdb->prepare() together, ensuring proper parameter binding.
The PagBank / PagSeguro Connect para WooCommerce plugin for WordPress is vulnerable to SQL Injection via the 'status' parameter in all versions up to, and including, 4.44.3 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Shop Manager-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
--- cache/charitable_1.8.8.4/charitable.php 2025-11-19 10:47:59.992280086 +0000+++ cache/charitable_1.8.8.5/charitable.php 2025-11-19 10:48:03.516505753 +0000@@ -3,11 +3,11 @@ * Plugin Name: Charitable * Plugin URI: https://www.wpcharitable.com * Description: The best WordPress donation plugin. Fundraising with recurring donations, and powerful features to help you raise more money online.- * Version: 1.8.8.4+ * Version: 1.8.8.5 * Author: Charitable Donations & Fundraising Team * Author URI: https://wpcharitable.com * Requires at least: 5.0- * Stable tag: 1.8.8.4+ * Stable tag: 1.8.8.5 * License: GPLv2 or later * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html *@@ -39,7 +39,7 @@ const AUTHOR = 'WP Charitable'; /* Plugin version. */- const VERSION = '1.8.8.4';+ const VERSION = '1.8.8.5'; /* Version of database schema. */ const DB_VERSION = '20180522';
Vulnerability Existed: no CWE-200: Exposure of Sensitive Information to an Unauthorized Actor - charitable.php [3,11,39] Old Code: ```php * Version: 1.8.8.4 * Stable tag: 1.8.8.4 const VERSION = '1.8.8.4'; ``` Fixed Code: ```php * Version: 1.8.8.5 * Stable tag: 1.8.8.5 const VERSION = '1.8.8.5'; ``` Explanation: The diff shows only version number updates from 1.8.8.4 to 1.8.8.5. These changes are routine version bumps with no security implications. No user input flows, no security sinks, and no vulnerability patterns are present in this version update diff.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/abstracts/abstract-class-charitable-query.php 2025-11-19 10:47:59.999280534 +0000+++ cache/charitable_1.8.8.5/includes/abstracts/abstract-class-charitable-query.php 2025-11-19 10:48:03.521506073 +0000@@ -673,7 +673,7 @@ */ public function where_donor_id_is_in( $where_statement ) { - $donor_email_passed = isset( $_GET['donor_email'] ) ? esc_html( $_GET['donor_email'] ) : false; // phpcs:ignore+ $donor_email_passed = isset( $_GET['donor_email'] ) ? sanitize_email( $_GET['donor_email'] ) : false; // phpcs:ignore $donor_email = $this->get( 'email', $donor_email_passed ); if ( $donor_email ) { // stop searching by ID, we will search by email that was supplied.@@ -730,7 +730,8 @@ /** * Filter query by donation ID(s). *- * @since 1.7.0.9+ * @since 1.7.0.9+ * @version 1.8.8.5 * * @global WPBD $wpdb * @param string $where_statement The default where statement.@@ -739,7 +740,7 @@ public function where_donation_id_is_in( $where_statement ) { global $wpdb; - $donation_ids_passed = isset( $_GET['donation_ids'] ) ? esc_html( $_GET['donation_ids'] ) : false; // phpcs:ignore+ $donation_ids_passed = isset( $_GET['donation_ids'] ) ? sanitize_text_field( $_GET['donation_ids'] ) : false; // phpcs:ignore if ( $donation_ids_passed === false ) { return $where_statement;@@ -752,7 +753,23 @@ return $where_statement; } - return $where_statement . " AND {$wpdb->posts}.ID IN ({$donation_ids_passed})";+ // Validate and sanitize each donation ID to ensure they are positive integers+ $valid_donation_ids = array();+ foreach ( $donation_ids as $donation_id ) {+ $donation_id = trim( $donation_id );+ if ( is_numeric( $donation_id ) && intval( $donation_id ) > 0 ) {+ $valid_donation_ids[] = intval( $donation_id );+ }+ }++ if ( empty( $valid_donation_ids ) ) {+ return $where_statement;+ }++ // Use proper parameterized query with placeholders+ $placeholders = $this->get_where_in_placeholders( $valid_donation_ids, 'charitable_validate_absint', '%d' );++ return $where_statement . " AND {$wpdb->posts}.ID IN ({$placeholders})"; } /**
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - includes/abstracts/abstract-class-charitable-query.php [739-752]
Old Code:
```php
$donation_ids_passed = isset( $_GET['donation_ids'] ) ? esc_html( $_GET['donation_ids'] ) : false; // phpcs:ignore
// ... (processing)
return $where_statement . " AND {$wpdb->posts}.ID IN ({$donation_ids_passed})";
```
Fixed Code:
```php
$donation_ids_passed = isset( $_GET['donation_ids'] ) ? sanitize_text_field( $_GET['donation_ids'] ) : false; // phpcs:ignore
// ... (processing with validation and parameterization)
$placeholders = $this->get_where_in_placeholders( $valid_donation_ids, 'charitable_validate_absint', '%d' );
return $where_statement . " AND {$wpdb->posts}.ID IN ({$placeholders})";
```
Explanation:
The old code used esc_html() on user input from $_GET['donation_ids'] and directly concatenated it into an SQL query. esc_html() is for HTML output escaping, not SQL injection prevention. The user-controlled value reached the SQL sink unmodified for SQL context, allowing SQL injection. The fixed code adds proper validation (ensuring positive integers) and uses parameterized queries via get_where_in_placeholders(), breaking the SQL injection vulnerability.
Vulnerability Existed: yes
TRUE POSITIVE
Improper Neutralization of Input During Web Page Generation (Cross-site Scripting) - CWE-79 - includes/abstracts/abstract-class-charitable-query.php [673]
Old Code:
```php
$donor_email_passed = isset( $_GET['donor_email'] ) ? esc_html( $_GET['donor_email'] ) : false; // phpcs:ignore
```
Fixed Code:
```php
$donor_email_passed = isset( $_GET['donor_email'] ) ? sanitize_email( $_GET['donor_email'] ) : false; // phpcs:ignore
```
Explanation:
The old code used esc_html() for email sanitization, which is insufficient for email validation. While esc_html() prevents XSS in HTML context, it doesn't validate email format. The fixed code uses sanitize_email(), which properly validates and sanitizes email addresses according to WordPress standards, providing better input validation for email fields.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/campaign-builder/fields/class-donation-options.php 2025-11-19 10:48:00.006280982 +0000+++ cache/charitable_1.8.8.5/includes/admin/campaign-builder/fields/class-donation-options.php 2025-11-19 10:48:03.528506521 +0000@@ -67,7 +67,8 @@ /** * Donation Options preview inside the builder. *- * @since 1.8.0+ * @since 1.8.0+ * @version 1.8.8.5 * * @param array $field_data Field data and settings. * @param array $campaign_data Campaign data and settings.@@ -77,8 +78,8 @@ public function field_preview( $field_data = false, $campaign_data = false, $field_id = false, $theme = '' ) { // Define data.- $placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : '';- $default_value = ! empty( $field['default_value'] ) ? $field['default_value'] : '';+ $placeholder = ! empty( $field_data['placeholder'] ) ? $field_data['placeholder'] : '';+ $default_value = ! empty( $field_data['default_value'] ) ? $field_data['default_value'] : ''; echo '<h4>' . esc_html( $this->name ) . '</h4>'; @@ -134,7 +135,7 @@ <?php - echo $charitable_builder_form_fields->generate_text(+ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['css_class'] ) ? $settings['css_class'] : false, esc_html__( 'CSS Class', 'charitable' ), array(
Vulnerability Existed: no Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-donation-options.php 77-78 Old Code: ```php $placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : ''; $default_value = ! empty( $field['default_value'] ) ? $field['default_value'] : ''; ``` Fixed Code: ```php $placeholder = ! empty( $field_data['placeholder'] ) ? $field_data['placeholder'] : ''; $default_value = ! empty( $field_data['default_value'] ) ? $field_data['default_value'] : ''; ``` Explanation: The vulnerability did not exist because the original code was using an undefined variable `$field` instead of the function parameter `$field_data`. Since `$field` was undefined, it would always be empty, making both `$placeholder` and `$default_value` empty strings regardless of user input. The fix corrects the variable name to use the actual parameter `$field_data`, but this is a bug fix rather than a security vulnerability since the original code couldn't be exploited due to the undefined variable.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/campaign-builder/fields/class-info-bar.php 2025-11-19 10:48:00.007281046 +0000+++ cache/charitable_1.8.8.5/includes/admin/campaign-builder/fields/class-info-bar.php 2025-11-19 10:48:03.528506521 +0000@@ -76,7 +76,7 @@ */ public function field_preview( $field_data = false, $campaign_data = false, $field_id = false, $theme = '' ) { - echo '<h4>' . $this->name . '</h4>';+ echo '<h4>' . esc_html( $this->name ) . '</h4>'; echo '<div class="charitable-field-preview-info-bar"><div class="row"> <div class="column">@@ -114,12 +114,12 @@ ?> <div class="charitable-campaign-info-bar">- <div <?php echo $css_class; ?>>+ <div <?php echo esc_attr( $css_class ); ?>> <div class="charitable-campaign-info-bar-row"> <?php if ( $show_donation_total ) : ?> <div class="charitable-campaign-info-column">- <?php echo $campaign->get_donation_summary(); ?>+ <?php echo wp_kses_post( $campaign->get_donation_summary() ); ?> </div> <?php endif; ?> @@ -128,8 +128,8 @@ <?php printf( /* translators: %s: number of donors */- _x( '%s Donors', 'number of donors', 'charitable' ),- '<span class="donors-count">' . $campaign->get_donor_count() . '</span>'+ esc_html_x( '%s Donors', 'number of donors', 'charitable' ),+ '<span class="donors-count">' . esc_html( $campaign->get_donor_count() ) . '</span>' ); ?> </div>@@ -143,7 +143,7 @@ $html = ob_get_clean(); - echo apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data );+ echo wp_kses_post( apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data ) ); } /**@@ -172,13 +172,13 @@ <div class="charitable-panel-field charitable-panel-field-section" data-field-id="<?php echo intval( $field_id ); ?>"> - <?php echo do_action( 'charitable_builder_' . $this->type . '_settings_display_start', $field_id, $campaign_data ); ?>+ <?php do_action( 'charitable_builder_' . $this->type . '_settings_display_start', $field_id, $campaign_data ); ?> </div> <?php - echo $charitable_builder_form_fields->generate_checkbox(+ echo $charitable_builder_form_fields->generate_checkbox( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['show_donors'] ) ? $settings['show_donors'] : false, esc_html__( 'Show Donors', 'charitable' ), array(@@ -190,7 +190,7 @@ ) ); - echo $charitable_builder_form_fields->generate_checkbox(+ echo $charitable_builder_form_fields->generate_checkbox( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['show_donation_total'] ) ? $settings['show_donation_total'] : false, esc_html__( 'Show Donation Total', 'charitable' ), array(@@ -205,7 +205,7 @@ /* CSS CLASS */ - echo $charitable_builder_form_fields->generate_text(+ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['css_class'] ) ? $settings['css_class'] : false, esc_html__( 'CSS Class', 'charitable' ), array(
Vulnerability Existed: yes FALSE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [76] Old Code: `echo '<h4>' . $this->name . '</h4>';` Fixed Code: `echo '<h4>' . esc_html( $this->name ) . '</h4>';` Explanation: The old code directly outputs `$this->name` without escaping. `$this->name` is a property that could contain user-controlled data from campaign builder settings. Since it's embedded in HTML context without sanitization, an attacker could inject malicious scripts. The fix adds `esc_html()` to properly escape the output. Vulnerability Existed: yes TRUE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [114] Old Code: `<div <?php echo $css_class; ?>>` Fixed Code: `<div <?php echo esc_attr( $css_class ); ?>>` Explanation: The old code directly outputs `$css_class` in HTML attribute context without escaping. `$css_class` comes from settings that could be user-controlled. Without proper escaping, an attacker could break out of the attribute context and inject malicious scripts. The fix adds `esc_attr()` to properly escape the attribute value. Vulnerability Existed: yes TRUE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [119] Old Code: `<?php echo $campaign->get_donation_summary(); ?>` Fixed Code: `<?php echo wp_kses_post( $campaign->get_donation_summary() ); ?>` Explanation: The old code directly outputs `$campaign->get_donation_summary()` without escaping. This method returns HTML content that could contain user-controlled data. Without proper sanitization, malicious scripts could be injected. The fix adds `wp_kses_post()` to allow only safe HTML tags. Vulnerability Existed: yes TRUE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [131-134] Old Code: ``` _x( '%s Donors', 'number of donors', 'charitable' ), '<span class="donors-count">' . $campaign->get_donor_count() . '</span>' ``` Fixed Code: ``` esc_html_x( '%s Donors', 'number of donors', 'charitable' ), '<span class="donors-count">' . esc_html( $campaign->get_donor_count() ) . '</span>' ``` Explanation: The old code uses `_x()` without escaping and directly outputs `$campaign->get_donor_count()` without escaping. Both the translation string and donor count could contain user-controlled data. The fix adds `esc_html_x()` for the translation and `esc_html()` for the donor count value. Vulnerability Existed: yes FALSE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [148] Old Code: `echo apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data );` Fixed Code: `echo wp_kses_post( apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data ) );` Explanation: The old code directly outputs the result of `apply_filters()` without escaping. Filter hooks allow other plugins to modify the output, which could introduce malicious content. The fix adds `wp_kses_post()` to sanitize the HTML output. Vulnerability Existed: yes FALSE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-info-bar.php [175] Old Code: `<?php echo do_action( 'charitable_builder_' . $this->type . '_settings_display_start', $field_id, $campaign_data ); ?>` Fixed Code: `<?php do_action( 'charitable_builder_' . $this->type . '_settings_display_start', $field_id, $campaign_data ); ?>` Explanation: The old code incorrectly uses `echo do_action()` instead of just `do_action()`. `do_action()` doesn't return a value, so this would output nothing, but the pattern suggests potential for output from action hooks. The fix removes the `echo` since action hooks should handle their own output.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/campaign-builder/fields/class-photo.php 2025-11-19 10:48:00.007281046 +0000+++ cache/charitable_1.8.8.5/includes/admin/campaign-builder/fields/class-photo.php 2025-11-19 10:48:03.529506585 +0000@@ -115,7 +115,7 @@ ?> <div class="charitable-campaign-primary-image">- <img <?php echo $css_class; ?> src="<?php echo esc_url( $image_url ); ?>" alt="<?php echo esc_attr( $alt_text ); ?>" <?php echo esc_attr( $photo_attr ); ?> />+ <img <?php echo esc_attr( $css_class ); ?> src="<?php echo esc_url( $image_url ); ?>" alt="<?php echo esc_attr( $alt_text ); ?>" <?php echo esc_attr( $photo_attr ); ?> /> </div> @@ -143,7 +143,7 @@ $html = $this->field_title( $this->name ); $html .= $this->field_wrapper( $this->render( $field_data, $campaign_data, $field_id, 'preview' ), $field_data ); - echo $html;+ echo wp_kses_post( $html ); } /**@@ -159,7 +159,7 @@ $html = $this->field_display_wrapper( $this->render( $field_data, $campaign_data ), $field_data ); - echo apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data );+ echo wp_kses_post( apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data ) ); } /**@@ -192,7 +192,7 @@ <?php - echo $charitable_builder_form_fields->generate_uploader(+ echo $charitable_builder_form_fields->generate_uploader( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['file'] ) ? $settings['file'] : false, esc_html__( 'Photo URL', 'charitable' ), array(@@ -206,7 +206,7 @@ ) ); - echo $charitable_builder_form_fields->generate_text(+ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['alt_text'] ) ? $settings['alt_text'] : false, esc_html__( 'ALT Text', 'charitable' ), array(@@ -217,7 +217,7 @@ ) ); - echo $charitable_builder_form_fields->generate_hidden_field(+ echo $charitable_builder_form_fields->generate_hidden_field( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['default'] ) ? $settings['default'] : false, array( 'id' => 'field_' . esc_attr( $this->type ) . '_default' . '_' . intval( $field_id ), // phpcs:ignore@@ -226,7 +226,7 @@ ) ); - echo $charitable_builder_form_fields->generate_number_slider(+ echo $charitable_builder_form_fields->generate_number_slider( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['width_percentage'] ) ? $settings['width_percentage'] : 100, esc_html__( 'Width', 'charitable' ), array(@@ -242,7 +242,7 @@ ) ); - echo $charitable_builder_form_fields->generate_align(+ echo $charitable_builder_form_fields->generate_align( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['align'] ) ? $settings['align'] : esc_attr( $this->align_default ), esc_html__( 'Align', 'charitable' ), array(@@ -252,7 +252,7 @@ ) ); - echo $charitable_builder_form_fields->generate_text(+ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['css_class'] ) ? $settings['css_class'] : false, esc_html__( 'CSS Class', 'charitable' ), array(@@ -293,7 +293,7 @@ <?php - echo $charitable_builder_form_fields->generate_number_slider(+ echo $charitable_builder_form_fields->generate_number_slider( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['width_percentage'] ) ? $settings['width_percentage'] : 100, esc_html__( 'Width', 'charitable' ), array(@@ -307,7 +307,7 @@ ) ); - echo $charitable_builder_form_fields->generate_align(+ echo $charitable_builder_form_fields->generate_align( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped isset( $settings['align'] ) ? $settings['align'] : false, esc_html__( 'Align', 'charitable' ), array(@@ -317,7 +317,7 @@ ) ); - echo $charitable_builder_form_fields->generate_text(+ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $settings['css_class'], esc_html__( 'CSS Class', 'charitable' ), array(
Vulnerability Existed: yes TRUE POSITIVE Cross-site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-photo.php 118 Old Code: `<img <?php echo $css_class; ?> src="<?php echo esc_url( $image_url ); ?>" alt="<?php echo esc_attr( $alt_text ); ?>" <?php echo esc_attr( $photo_attr ); ?> />` Fixed Code: `<img <?php echo esc_attr( $css_class ); ?> src="<?php echo esc_url( $image_url ); ?>" alt="<?php echo esc_attr( $alt_text ); ?>" <?php echo esc_attr( $photo_attr ); ?> />` Explanation: The $css_class variable was directly output without escaping in the img tag attributes. User-controlled CSS class data could contain malicious JavaScript via event handlers or break out of the attribute context. The fix adds esc_attr() to properly escape the $css_class value for HTML attribute context. Vulnerability Existed: yes FALSE POSITIVE Cross-site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-photo.php 146 Old Code: `echo $html;` Fixed Code: `echo wp_kses_post( $html );` Explanation: The $html variable containing field title and wrapper HTML was directly echoed without sanitization. User-controlled data in field titles or other components could contain malicious scripts. The fix adds wp_kses_post() to filter the HTML output and remove unsafe elements/attributes. Vulnerability Existed: yes FALSE POSITIVE Cross-site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/fields/class-photo.php 162 Old Code: `echo apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data );` Fixed Code: `echo wp_kses_post( apply_filters( 'charitable_campaign_builder_' . $this->type . '_field_display', $html, $campaign_data ) );` Explanation: The filtered HTML output from apply_filters was directly echoed without sanitization. The filter could return user-controlled or modified HTML containing malicious scripts. The fix adds wp_kses_post() to sanitize the filtered output before echoing.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/campaign-builder/panels/settings/class-settings-donation-options.php 2025-11-19 10:48:00.013281431 +0000+++ cache/charitable_1.8.8.5/includes/admin/campaign-builder/panels/settings/class-settings-donation-options.php 2025-11-19 10:48:03.538507161 +0000@@ -75,7 +75,7 @@ $active = ( true === apply_filters( 'charitable_campaign_builder_settings_sidebar_active', $this->active, $this->slug ) ) ? 'active' : false; - echo '<a href="#" class="charitable-panel-sidebar-section charitable-panel-sidebar-section-' . $this->slug . ' ' . $active . '" data-section="' . $this->slug . '">' . $this->primary_label . ' <i class="fa fa-angle-right charitable-toggle-arrow"></i></a>';+ echo '<a href="#" class="charitable-panel-sidebar-section charitable-panel-sidebar-section-' . esc_attr( $this->slug ) . ' ' . esc_attr( $active ) . '" data-section="' . esc_attr( $this->slug ) . '">' . esc_html( $this->primary_label ) . ' <i class="fa fa-angle-right charitable-toggle-arrow"></i></a>'; } /**@@ -143,42 +143,42 @@ <?php - echo $charitable_builder_form_fields->generate_donation_amounts(- $settings->campaign_data_settings( 'donation_amounts', 'donation-options' ),- esc_html__( 'Suggested Donation Amounts', 'charitable' ),- array(- 'id' => 'campaign_donation_amounts',- 'name' => array( 'settings', esc_attr( $this->slug ), 'donation_amounts' ),- 'default' => $settings->campaign_data_settings( 'suggested_donations_default', 'donation-options' ),- )- );-- echo $charitable_builder_form_fields->generate_text(- $settings->campaign_data_settings( 'minimum_donation_amount', 'donation-options' ),- esc_html__( 'Minimum Donation Amount', 'charitable' ),- array(- 'id' => 'campaign_minimum_donation_amount',- 'name' => array( 'settings', esc_attr( $this->slug ), 'minimum_donation_amount' ),- 'placeholder' => '',- // 'add_commas' => true,- 'description' => esc_html__( 'Leave empty to allow no restrictions on how small the donation can be.', 'charitable' ),- 'icon' => function_exists( 'charitable_get_currency_helper' ) ? charitable_get_currency_helper()->get_currency_symbol() : 'images/campaign-builder/settings/goal_dollar.png',- 'container_class' => 'charitable-format-money',- )- );+ echo $charitable_builder_form_fields->generate_donation_amounts( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped+ $settings->campaign_data_settings( 'donation_amounts', 'donation-options' ),+ esc_html__( 'Suggested Donation Amounts', 'charitable' ),+ array(+ 'id' => 'campaign_donation_amounts',+ 'name' => array( 'settings', esc_attr( $this->slug ), 'donation_amounts' ),+ 'default' => $settings->campaign_data_settings( 'suggested_donations_default', 'donation-options' ),+ )+ );++ echo $charitable_builder_form_fields->generate_text( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped+ $settings->campaign_data_settings( 'minimum_donation_amount', 'donation-options' ),+ esc_html__( 'Minimum Donation Amount', 'charitable' ),+ array(+ 'id' => 'campaign_minimum_donation_amount',+ 'name' => array( 'settings', esc_attr( $this->slug ), 'minimum_donation_amount' ),+ 'placeholder' => '',+ // 'add_commas' => true,+ 'description' => esc_html__( 'Leave empty to allow no restrictions on how small the donation can be.', 'charitable' ),+ 'icon' => function_exists( 'charitable_get_currency_helper' ) ? charitable_get_currency_helper()->get_currency_symbol() : 'images/campaign-builder/settings/goal_dollar.png',+ 'container_class' => 'charitable-format-money',+ )+ ); $default_allow_custom = ! empty( $_GET['campaign_id'] ) ? $settings->campaign_data_settings( 'allow_custom_donations', 'donation-options' ) : '1'; - echo $charitable_builder_form_fields->generate_toggle(- $default_allow_custom,- esc_html__( 'Allow Custom Donations', 'charitable' ),- array(- 'id' => 'campaign_allow_custom_donations',- 'checked_value' => '1',- 'name' => array( 'settings', esc_attr( $this->slug ), 'allow_custom_donations' ),- 'container_class' => 'charitable-campaign-builder-allow-custom-donations',- )- );+ echo $charitable_builder_form_fields->generate_toggle( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped+ $default_allow_custom,+ esc_html__( 'Allow Custom Donations', 'charitable' ),+ array(+ 'id' => 'campaign_allow_custom_donations',+ 'checked_value' => '1',+ 'name' => array( 'settings', esc_attr( $this->slug ), 'allow_custom_donations' ),+ 'container_class' => 'charitable-campaign-builder-allow-custom-donations',+ )+ ); do_action( 'charitable_campaign_builder_settings_donation_options_after', $this->active, $this->slug ); @@ -190,7 +190,7 @@ $html = ob_get_clean(); - echo $html;+ echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } }
Vulnerability Existed: no Cross-Site Scripting (XSS) - CWE-79 - includes/admin/campaign-builder/panels/settings/class-settings-donation-options.php [75,143-190] Explanation: The diff shows the addition of proper output escaping. In line 75, `$this->slug` and `$active` are now properly escaped with `esc_attr()`, and `$this->primary_label` is escaped with `esc_html()`. For the form field generation methods, while the direct output of these methods is not escaped (as indicated by the phpcs ignore comments), these are framework methods that generate form fields and are expected to handle their own escaping internally. The final HTML output in line 190 is also marked with a phpcs ignore comment, but this output comes from ob_get_clean() which contains properly escaped content from the form field generation methods. The changes demonstrate improved security practices by adding explicit escaping where needed.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/export-items/class-charitable-export-items.php 2025-11-19 10:48:00.019281815 +0000+++ cache/charitable_1.8.8.5/includes/admin/export-items/class-charitable-export-items.php 2025-11-19 10:48:03.551507994 +0000@@ -82,10 +82,10 @@ $export_args = $_POST['charitable_settings']['export']; // phpcs:ignore if ( ! isset( $export_args['export_campaign'] ) || intval( $export_args['export_campaign'] ) === 0 ) {- if ( charitable_is_debug() ) {- error_log( 'admin_accept_export_campaign_request: ' );- error_log( print_r( $export_args, true ) );- }+ if ( charitable_is_debug() ) {+ error_log( 'admin_accept_export_campaign_request: ' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log( print_r( $export_args, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r+ } return; }
Vulnerability Existed: no
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor - CWE-200 - includes/admin/export-items/class-charitable-export-items.php [84-87]
Old Code:
```php
if ( charitable_is_debug() ) {
error_log( 'admin_accept_export_campaign_request: ' );
error_log( print_r( $export_args, true ) );
}
```
Fixed Code:
```php
if ( charitable_is_debug() ) {
error_log( 'admin_accept_export_campaign_request: ' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( print_r( $export_args, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
}
```
Explanation:
The code change only adds PHPCS ignore comments for error_log and print_r functions. The debug logging functionality remains identical - it only executes when charitable_is_debug() returns true, which is a controlled environment setting. User input ($export_args) is only logged in debug mode, which is not accessible to unauthorized users in production. This does not expose sensitive information to unauthorized actors in normal operation.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/forms/class-charitable-admin-donation-form.php 2025-11-19 10:48:00.019281815 +0000+++ cache/charitable_1.8.8.5/includes/admin/forms/class-charitable-admin-donation-form.php 2025-11-19 10:48:03.551507994 +0000@@ -619,7 +619,8 @@ /** * Sanitize the date. *- * @since 1.5.0+ * @since 1.5.0+ * @version 1.8.8.5 * * @param array $values The submitted values. * @return array@@ -638,9 +639,22 @@ $values['date_gmt'] = date( 'Y-m-d H:i:s' ); } - /* If the donation date has been changed, the time is always set to 00:00:00 */+ /* If the donation date has been changed, preserve the original time from the donation log */ if ( $values['date_gmt'] !== $donation->post_date_gmt && ! $is_new ) {- $values['date_gmt'] = $date . ' 00:00:00';+ // Get the original donation time from the donation log+ $donation_log = get_post_meta( $donation->ID, '_donation_log', true );+ $original_time = '00:00:00'; // Default fallback++ if ( is_array( $donation_log ) && ! empty( $donation_log ) ) {+ // Get the first log entry which contains the original creation time+ $first_log_entry = $donation_log[0];+ if ( isset( $first_log_entry['time'] ) ) {+ // Convert the original timestamp to GMT time format+ $original_time = gmdate( 'H:i:s', $first_log_entry['time'] );+ }+ }++ $values['date_gmt'] = $date . ' ' . $original_time; } return $values;
Vulnerability Existed: no
CWE-352: Cross-Site Request Forgery - CWE-352 - includes/admin/forms/class-charitable-admin-donation-form.php [619-660]
Old Code:
```php
/* If the donation date has been changed, the time is always set to 00:00:00 */
if ( $values['date_gmt'] !== $donation->post_date_gmt && ! $is_new ) {
$values['date_gmt'] = $date . ' 00:00:00';
}
```
Fixed Code:
```php
/* If the donation date has been changed, preserve the original time from the donation log */
if ( $values['date_gmt'] !== $donation->post_date_gmt && ! $is_new ) {
// Get the original donation time from the donation log
$donation_log = get_post_meta( $donation->ID, '_donation_log', true );
$original_time = '00:00:00'; // Default fallback
if ( is_array( $donation_log ) && ! empty( $donation_log ) ) {
// Get the first log entry which contains the original creation time
$first_log_entry = $donation_log[0];
if ( isset( $first_log_entry['time'] ) ) {
// Convert the original timestamp to GMT time format
$original_time = gmdate( 'H:i:s', $first_log_entry['time'] );
}
}
$values['date_gmt'] = $date . ' ' . $original_time;
}
```
Explanation:
The code change is a functionality improvement to preserve original donation time when updating donation dates. The user input `$date` comes from form submission but is validated through WordPress nonce checks earlier in the form processing. The `$date` value is used in date string concatenation but is not used in any security-sensitive context like SQL queries, file operations, or output. The change only affects how the GMT date string is constructed for donation records, with no security vulnerability introduced or fixed.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/onboarding/class-charitable-checklist.php 2025-11-19 10:48:00.021281943 +0000+++ cache/charitable_1.8.8.5/includes/admin/onboarding/class-charitable-checklist.php 2025-11-19 10:48:03.555508250 +0000@@ -1239,8 +1239,8 @@ // Pro plugin doesn't exist - don't deactivate Lite version // Clear the option to prevent future attempts delete_option( 'charitable_activate_pro' );- // Log this for debugging- error_log( 'Charitable: Pro plugin not found at ' . $pro_plugin_path . ' - preventing Lite deactivation' );+ // Log this for debugging+ error_log( 'Charitable: Pro plugin not found at ' . $pro_plugin_path . ' - preventing Lite deactivation' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log return; }
Vulnerability Existed: no CWE-117: Improper Output Neutralization for Logs - CWE-117 - includes/admin/onboarding/class-charitable-checklist.php [1242] Old Code: error_log( 'Charitable: Pro plugin not found at ' . $pro_plugin_path . ' - preventing Lite deactivation' ); Fixed Code: error_log( 'Charitable: Pro plugin not found at ' . $pro_plugin_path . ' - preventing Lite deactivation' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log Explanation: The change only adds a PHPCS ignore comment for the error_log function usage. The variable $pro_plugin_path contains a filesystem path constructed earlier in the code (not shown in diff), not direct user input. Since this is a debug log statement in an admin context and the path value is controlled by the application logic rather than external user input, there is no log injection vulnerability. The code change does not affect security.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/onboarding/class-charitable-setup.php 2025-11-19 10:48:00.021281943 +0000+++ cache/charitable_1.8.8.5/includes/admin/onboarding/class-charitable-setup.php 2025-11-19 10:48:03.556508314 +0000@@ -1531,8 +1531,8 @@ if ( $should_activate_pro ) { update_option( 'charitable_activate_pro', true ); } else {- // Log this for debugging- error_log( 'Charitable: Pro plugin not found during setup completion - skipping Pro activation' );+ // Log this for debugging+ error_log( 'Charitable: Pro plugin not found during setup completion - skipping Pro activation' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } wp_send_json_success(
Vulnerability Existed: no CWE Name - CWE ID - File includes/admin/onboarding/class-charitable-setup.php Lines 1534-1535 Old Code: ```php error_log( 'Charitable: Pro plugin not found during setup completion - skipping Pro activation' ); ``` Fixed Code: ```php error_log( 'Charitable: Pro plugin not found during setup completion - skipping Pro activation' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log ``` Explanation: The change only adds a PHP Code Sniffer ignore comment for the error_log function. The logged message is a fixed string with no user input. There is no entry point for attacker-controlled data, no transformation or validation needed, and no security vulnerability introduced or fixed. The modification is purely related to code style/standards compliance.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/admin/reports/class-charitable-reports-download.php 2025-11-19 10:48:00.022282007 +0000+++ cache/charitable_1.8.8.5/includes/admin/reports/class-charitable-reports-download.php 2025-11-19 10:48:03.559508506 +0000@@ -301,7 +301,7 @@ ignore_user_abort( true ); if ( ! charitable_is_func_disabled( 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {- set_time_limit( 0 );+ set_time_limit( 0 ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged } if ( '' !== $report_type ) {
Vulnerability Existed: no CWE Name - CWE ID - File includes/admin/reports/class-charitable-reports-download.php [Lines 304] Old Code: ```php set_time_limit( 0 ); ``` Fixed Code: ```php set_time_limit( 0 ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged ``` Explanation: The change only adds a PHP CodeSniffer ignore comment for a discouraged function. There is no user input flowing to the `set_time_limit` function call, and the parameter is hardcoded as `0`. This is a code style/standards change with no security implications.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/includes/stripe/gateway/class-charitable-stripe-product.php 2025-11-19 10:48:00.064284697 +0000+++ cache/charitable_1.8.8.5/includes/stripe/gateway/class-charitable-stripe-product.php 2025-11-19 10:48:03.613511964 +0000@@ -154,7 +154,7 @@ } catch ( Exception $e ) { /* Log the error message and return false. */- error_log( 'STRIPE - Error creating product: ' . $e->getMessage() );+ error_log( 'STRIPE - Error creating product: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log return false; }
Vulnerability Existed: no CWE-117: Improper Output Neutralization for Logs - CWE ID 117 - includes/stripe/gateway/class-charitable-stripe-product.php 157 Old Code: `error_log( 'STRIPE - Error creating product: ' . $e->getMessage() );` Fixed Code: `error_log( 'STRIPE - Error creating product: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log` Explanation: The change only adds a PHPCS ignore comment for the error_log function usage. The user input ($e->getMessage()) flows directly into error_log without sanitization in both versions. However, error_log writes to server logs, not to user-facing output, so this does not create a cross-site scripting vulnerability. The CWE-117 classification applies to log forging where attacker-controlled input could corrupt log files, but the code behavior remains identical between versions with no security improvement or regression.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/templates/donation-form/donor-fields/donor-details.php 2025-11-19 10:48:00.080285721 +0000+++ cache/charitable_1.8.8.5/templates/donation-form/donor-fields/donor-details.php 2025-11-19 10:48:03.644513949 +0000@@ -24,19 +24,19 @@ ?> <div class="charitable-donor-details">- <address class="donor-address"><?php echo $user->get_address(); ?></address>+ <address class="donor-address"><?php echo wp_kses_post( $user->get_address() ); ?></address> <p class="donor-contact-details"> <?php /* translators: %s: email address */- printf( __( 'Email: %s', 'charitable' ), $user->user_email );+ printf( esc_html__( 'Email: %s', 'charitable' ), esc_html( $user->user_email ) ); if ( ! empty( $user->get( 'donor_phone' ) ) ) : /* translators: %s: phone number */- echo '<br />' . sprintf( __( 'Phone number: %s', 'charitable' ), $user->get( 'donor_phone' ) );+ echo '<br />' . sprintf( esc_html__( 'Phone number: %s', 'charitable' ), esc_html( $user->get( 'donor_phone' ) ) ); endif; ?> </p> <p class="charitable-change-user-details">- <a href="#" data-charitable-toggle="charitable-user-fields"><?php _e( 'Update your details', 'charitable' ); ?></a>+ <a href="#" data-charitable-toggle="charitable-user-fields"><?php esc_html_e( 'Update your details', 'charitable' ); ?></a> </p><!-- .charitable-change-user-details --> </div><!-- .charitable-donor-details -->
Vulnerability Existed: yes TRUE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - templates/donation-form/donor-fields/donor-details.php 27,30,36 Old Code: ```php <address class="donor-address"><?php echo $user->get_address(); ?></address> printf( __( 'Email: %s', 'charitable' ), $user->user_email ); echo '<br />' . sprintf( __( 'Phone number: %s', 'charitable' ), $user->get( 'donor_phone' ) ); _e( 'Update your details', 'charitable' ); ``` Fixed Code: ```php <address class="donor-address"><?php echo wp_kses_post( $user->get_address() ); ?></address> printf( esc_html__( 'Email: %s', 'charitable' ), esc_html( $user->user_email ) ); echo '<br />' . sprintf( esc_html__( 'Phone number: %s', 'charitable' ), esc_html( $user->get( 'donor_phone' ) ) ); esc_html_e( 'Update your details', 'charitable' ); ``` Explanation: The old code contained multiple XSS vulnerabilities where user-controlled data was directly output without proper escaping. The user address from `$user->get_address()` was echoed directly without escaping (line 27). User email and phone number values were inserted into translated strings without escaping (lines 30, 36). The translation string for "Update your details" was output without escaping (line 42). The fixed code adds proper escaping: `wp_kses_post()` for HTML content in the address, `esc_html()` for email and phone values, and `esc_html_e()` for the translated link text, preventing malicious script injection.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/templates/donation-form/meta-fields.php 2025-11-19 10:48:00.080285721 +0000+++ cache/charitable_1.8.8.5/templates/donation-form/meta-fields.php 2025-11-19 10:48:03.645514013 +0000@@ -28,7 +28,7 @@ ?> <div id="charitable-meta-fields"> <?php if ( isset( $field['legend'] ) ) : ?>- <div class="charitable-form-header"><?php echo $field['legend']; ?></div>+ <div class="charitable-form-header"><?php echo esc_html( $field['legend'] ); ?></div> <?php endif; ?> <?php $form->view()->render_fields( $fields ); ?> </div><!-- #charitable-meta-fields -->
Vulnerability Existed: yes FALSE POSITIVE Cross-site Scripting (XSS) - CWE-79 - templates/donation-form/meta-fields.php 30 Old Code: ```php <div class="charitable-form-header"><?php echo $field['legend']; ?></div> ``` Fixed Code: ```php <div class="charitable-form-header"><?php echo esc_html( $field['legend'] ); ?></div> ``` Explanation: The old code directly outputs `$field['legend']` without escaping. User input could enter `$field['legend']` through donation form field definitions. Since the value is echoed unescaped into HTML context, an attacker-controlled value reaches the sink unsanitized, enabling XSS. The fix adds `esc_html()` to properly escape the output.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/charitable_1.8.8.4/templates/emails/footer.php 2025-11-19 10:48:00.081285785 +0000+++ cache/charitable_1.8.8.5/templates/emails/footer.php 2025-11-19 10:48:03.646514077 +0000@@ -73,7 +73,7 @@ ) ) ) ); - echo $footer_content;+ echo wp_kses_post( $footer_content ); ?> </td> </tr>
Vulnerability Existed: yes TRUE POSITIVE Cross-site Scripting (XSS) - CWE-79 - templates/emails/footer.php 76 Old Code: ```php echo $footer_content; ``` Fixed Code: ```php echo wp_kses_post( $footer_content ); ``` Explanation: The user-controlled variable `$footer_content` was directly echoed without sanitization in the old code. The variable originates from `charitable_get_email_footer_content()` which retrieves content that can be modified through WordPress admin settings. Since this content is rendered in an email footer HTML context, an attacker with admin access could inject malicious scripts. The fix adds `wp_kses_post()` which sanitizes HTML content by allowing only safe HTML tags and attributes, preventing XSS.
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to SQL Injection via the donation_ids parameter in all versions up to, and including, 1.8.8.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation of the vulnerability requires a paid donation.
--- cache/squirrly-seo_12.4.05/squirrly.php 2025-11-19 10:49:53.295537040 +0000+++ cache/squirrly-seo_12.4.06/squirrly.php 2025-11-19 10:49:55.594684334 +0000@@ -9,7 +9,7 @@ * Description: AI Private SEO Consultant that Brings You the Full Force of SEO: All Schema Rich Results, Inner Links, Redirects, AI Research, Real-Time SEO Content, Traffic and SEO Audits, SERP Checker. * Author: Squirrly * Author URI: https://plugin.squirrly.co - * Version: 12.4.05 + * Version: 12.4.06 * License: GPLv2 or later * License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * Text Domain: squirrly-seo @@ -18,9 +18,9 @@ if ( ! defined( 'SQ_VERSION' ) ) { /* SET THE CURRENT VERSION ABOVE AND BELOW */ - define( 'SQ_VERSION', '12.4.05' ); + define( 'SQ_VERSION', '12.4.06' ); //The last stable version - define( 'SQ_STABLE_VERSION', '12.4.04' ); + define( 'SQ_STABLE_VERSION', '12.4.05' ); // Call config files try { include_once dirname( __FILE__ ) . '/config/config.php';
Vulnerability Existed: no CWE-200: Exposure of Sensitive Information to an Unauthorized Actor - CWE-200 - squirrly.php [9,18,21] Old Code: ```php * Version: 12.4.05 ``` ```php define( 'SQ_VERSION', '12.4.05' ); ``` ```php define( 'SQ_STABLE_VERSION', '12.4.04' ); ``` Fixed Code: ```php * Version: 12.4.06 ``` ```php define( 'SQ_VERSION', '12.4.06' ); ``` ```php define( 'SQ_STABLE_VERSION', '12.4.05' ); ``` Explanation: The diff shows only version number updates from 12.4.05 to 12.4.06 for the plugin version and from 12.4.04 to 12.4.05 for the stable version. These are metadata changes that don't involve user input processing, data validation, or security-sensitive operations. No user-controlled data flows to any sinks, and no code logic changes are present that could introduce or fix vulnerabilities.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in SEO Squirrly SEO Plugin by Squirrly SEO allows SQL Injection.This issue affects SEO Plugin by Squirrly SEO: from n/a through 12.4.03.
--- cache/hydra-booking_1.1.10/admin/Controller/AvailabilityController.php+++ /dev/null@@ -1,130 +0,0 @@-<?php-namespace HydraBooking\Admin\Controller;-// exit-if ( ! defined( 'ABSPATH' ) ) { exit; }--// Use DB-use HydraBooking\DB\Availability;-use HydraBooking\Admin\Controller\RouteController;---class AvailabilityController {-- public $time_zone = array();-- // constaract- public function __construct() {- // add_action('admin_init', array($this, 'init'));- // $DateTimeZone = new \DateTimeZone( 'UTC' );- // $this->time_zone = $DateTimeZone->listIdentifiers(); - }-- public function init() {- }-- // public function create_endpoint() {- // register_rest_route(- // 'hydra-booking/v1',- // '/availability',- // array(- // 'methods' => 'GET',- // 'callback' => array( $this, 'get_all' ),- // 'permission_callback' => array(new RouteController() , 'permission_callback'),- // )- // );- // register_rest_route(- // 'hydra-booking/v1',- // '/availability/(?P<id>[0-9]+)/',- // array(- // 'methods' => 'GET',- // 'callback' => array( $this, 'get_items' ),- // 'permission_callback' => array(new RouteController() , 'permission_callback'),- // )- // );- // register_rest_route(- // 'hydra-booking/v1',- // '/availability/create/',- // array(- // 'methods' => 'POST',- // 'callback' => array( $this, 'create' ),- // 'permission_callback' => array(new RouteController() , 'permission_callback'),- // )- // );- // register_rest_route(- // 'hydra-booking/v1',- // '/availability/update/',- // array(- // 'methods' => 'POST',- // 'callback' => array( $this, 'update' ),- // 'permission_callback' => array(new RouteController() , 'permission_callback'),- // )- // );- // register_rest_route(- // 'hydra-booking/v1',- // '/availability/delete/(?P<id>[0-9]+)/',- // array(- // 'methods' => 'GET',- // 'callback' => array( $this, 'delete' ),- // 'permission_callback' => array(new RouteController() , 'permission_callback'),- // )- // );- // } -- // public function create() {- // $data = json_decode( file_get_contents( 'php://input' ), true );-- // $Availability = new Availability();- // $insert = $Availability->add( $data );-- // return rest_ensure_response( $insert );- // // return $data;- // }-- // // update- // public function update() {- // $data = json_decode( file_get_contents( 'php://input' ), true );- // $Availability = new Availability();- // $update = $Availability->update( $data );- // return rest_ensure_response( $data );- // // return $data;- // }-- // // delete- // public function delete( $request ) {- // $id = $request['id'];- // $Availability = new Availability();- // $Availability->delete( $id );-- // $data = array(- // 'status' => true,- // 'message' => __('Availability Deleted Successfully', 'hydra-booking'),-- // );- // return rest_ensure_response( $data );- // // return $data;- // }-- // public function get_all() {- // $Availability = new Availability();- // $Availability = $Availability->get();-- // $data = array(- // 'status' => true,- // 'availability' => $Availability,- // 'time_zone' => $this->time_zone,- // );- // return rest_ensure_response( $data );- // }-- // public function get_items( $request ) {- // $id = $request['id'];- // $Availability = new Availability();- // $Availability = $Availability->get( $id );- // $data = array(- // 'status' => true,- // 'availability' => $Availability,- // 'time_zone' => $this->time_zone,- // );- // return rest_ensure_response( $data );- // }-}
Vulnerability Existed: no CWE-89: Improper Neutralization of Special Elements used in an SQL Command - admin/Controller/AvailabilityController.php [Lines 1-130] Old Code: ```php // All commented code removed ``` Fixed Code: ```php // File completely removed ``` Explanation: The entire file has been removed, eliminating all previously commented-out code. Since no active code remains, there are no entry points for user input, no data transformations, and no sinks. The removal of this file means no SQL injection or other vulnerabilities can exist in this component.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/BookingController.php 2025-11-19 10:50:13.125807496 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/BookingController.php 2025-11-19 10:50:25.776618038 +0000@@ -231,7 +231,7 @@ array( 'methods' => 'GET', 'callback' => array( $this, 'filterBookings' ),- 'permission_callback' => array(new RouteController() , 'permission_callback'),+ 'permission_callback' => array(new RouteController() , 'tfhb_manage_options_permission'), 'args' => array( 'title' => array( 'sanitize_callback' => 'sanitize_text_field',
Vulnerability Existed: no CWE-862: Missing Authorization - CWE-862 - admin/Controller/BookingController.php [231] Old Code: ```php 'permission_callback' => array(new RouteController() , 'permission_callback'), ``` Fixed Code: ```php 'permission_callback' => array(new RouteController() , 'tfhb_manage_options_permission'), ``` Explanation: The change replaces a generic permission callback with a specific one named "tfhb_manage_options_permission". The original "permission_callback" method name suggests it might have been a general or potentially insufficient authorization check. The new method name explicitly indicates it checks for "manage_options" capability, which is a WordPress administrative privilege. This change strengthens authorization by using a more specific permission check, but does not indicate a vulnerability existed in the previous version since we cannot determine the implementation of the original permission_callback method.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/DateTimeController.php 2025-11-19 10:50:13.126807560 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/DateTimeController.php 2025-11-19 10:50:25.777618103 +0000@@ -97,9 +97,10 @@ return $start_format . ' - ' . $end_format . ' (' . $selected_time_zone . ')'; } }- public function getAvailableTimeData( $meeting_id, $selected_date, $selected_time_zone, $selected_time_format ) {+ public function getAvailableTimeData( $meeting_id, $selected_date, $selected_time_zone, $selected_time_format, $host_id = 0 ) { $meeting_id = isset( $meeting_id ) ? $meeting_id : '';+ $host_id = isset( $host_id ) ? $host_id : 0; $selected_date = isset( $selected_date ) ? sanitize_text_field( $selected_date ) : ''; @@ -151,11 +152,15 @@ // Get All Booking Data. $booking = new Booking(); - $where = array(- array('meeting_id', '=', $meeting_id),- array('meeting_dates', '=', $selected_date), - array('status', '!=', 'canceled'),- );+ // + $where = [+ 'OR' => [+ ['host_id', '=', $MeetingsData->host_id],+ ['meeting_id', '=', $meeting_id]+ ],+ ['meeting_dates', '=', $selected_date], + ['status', '!=', 'canceled'],+ ]; $bookings = $booking->getBookingWithAttendees( $where, null,
Vulnerability Existed: no
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') - admin/Controller/DateTimeController.php 151-165
Old Code:
```php
$where = array(
array('meeting_id', '=', $meeting_id),
array('meeting_dates', '=', $selected_date),
array('status', '!=', 'canceled'),
);
```
Fixed Code:
```php
$where = [
'OR' => [
['host_id', '=', $MeetingsData->host_id],
['meeting_id', '=', $meeting_id]
],
['meeting_dates', '=', $selected_date],
['status', '!=', 'canceled'],
];
```
Explanation:
The code change is a functional modification, not a security fix. Both versions use parameterized queries through the framework's query builder pattern. The `$booking->getBookingWithAttendees()` method appears to use bound parameters or a safe ORM approach, as evidenced by the array structure with column names, operators, and values. User input `$meeting_id` and `$selected_date` are passed as values in the where clause array structure, not concatenated into SQL strings. The framework likely handles this safely through prepared statements or proper escaping. No SQL injection vulnerability exists in either version.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/Helper.php 2025-11-19 10:50:13.127807624 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/Helper.php 2025-11-19 10:50:25.778618167 +0000@@ -16,6 +16,9 @@ $notification = array( 'host' => array(), 'attendee' => array(),+ 'telegram' => array(),+ 'twilio' => array(),+ 'slack' => array(), ); // Get image URL dynamically@@ -29,7 +32,7 @@ // Host Notification- $notification['host']['booking_confirmation'] = array(+ $notification['host']['booking_confirmation'] = array( 'status' => 1, 'template' => 'default', 'from' => '{{wp.admin_email}}',@@ -190,10 +193,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -513,10 +516,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -836,10 +839,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -1159,10 +1162,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -1480,10 +1483,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -1803,10 +1806,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -1964,7 +1967,6 @@ ) );- // Attendee Notification $notification['attendee']['booking_pending'] = array( 'status' => 1, 'template' => 'default',@@ -2127,10 +2129,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -2449,10 +2451,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -2773,10 +2775,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -3094,10 +3096,10 @@ </tr> <tr> <td style="font-size: 15px;"><ul><li>Please <strong>join the event five minutes before the event starts</strong> based on your time zone.</li><li>Ensure you have a good internet connection, a quality camera, and a quiet space.</li></ul></td>- </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr>+ </tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="padding: 16px 0;width: 100%; max-width: 600px; margin: 0 auto;" class="tfhb-cancel-reschedule-btn"><tbody><tr><td><table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-top: 1px dashed #C0D8C4;border-bottom: 1px dashed #C0D8C4; padding: 0 32px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr> <td style="font-size: 15px;padding: 24px 0 16px 0;">You can cancel or reschedule this event for any reason.</td> </tr><tr>- <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table>+ <td style="font-size: 15px; padding-bottom: 24px;"><a href="{{booking.cancel_link}}" class="tfhb-cancel-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block;text-decoration: none;">Cancel</a><a href="{{booking.rescheduled_link}}" class="tfhb-reschedule-btn" style=" padding: 8px 24px; border-radius: 8px;border: 1px solid #C0D8C4;background: #FFF; color: #273F2B;display: inline-block; margin-left: 16px;text-decoration: none;">Reschedule</a></td></tr></tbody></table></td></tr></tbody></table> <table role="presentation" cellspacing="0" cellpadding="0" border="0" bgcolor="#121D13" style="padding: 16px 32px;border-radius: 0px 0px 8px 8px; width: 100%; max-width: 600px; margin: 0 auto;"> <tbody><tr><td align="left">@@ -3255,6 +3257,92 @@ ) ); + // Telegram Notification+ $notification['telegram']['booking_confirmation'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>A new Booking has been scheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['telegram']['booking_cancel'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Cancellation</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['telegram']['booking_reschedule'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Rescheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );++ // Twilio Notification+ $notification['twilio']['booking_confirmation'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>A new Booking has been scheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['twilio']['booking_cancel'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Cancellation</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['twilio']['booking_reschedule'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Rescheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ + // Slack Notification+ $notification['slack']['booking_confirmation'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>A new Booking has been scheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['slack']['booking_cancel'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Cancellation</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ );+ $notification['slack']['booking_reschedule'] = array(+ 'status' => 0,+ 'builder' => '',+ 'body' => '+ <h3>Booking Rescheduled</h3> <hr> + <h4>Meeting Details</h4>+ <p> {{meeting.title}} with {{attendee.name}}</p> + <p> Date: {{meeting.date}} </p>'+ ); return $notification;
Vulnerability Existed: no
No specific vulnerability - CWE-79 - admin/Controller/Helper.php [Multiple lines]
Old Code:
Various HTML template strings with inline styles and template variables like {{booking.cancel_link}}, {{booking.rescheduled_link}}, {{meeting.title}}, {{attendee.name}}, etc.
Fixed Code:
Added CSS classes (tfhb-cancel-reschedule-btn, tfhb-cancel-btn, tfhb-reschedule-btn) and new notification arrays for telegram, twilio, and slack services.
Explanation:
The diff shows template improvements and feature additions, not security fixes. The changes involve:
1. Adding CSS classes to HTML elements for better styling control
2. Adding new notification configuration arrays for telegram, twilio, and slack services
3. Minor formatting adjustments to existing HTML email templates
All template variables ({{booking.cancel_link}}, {{booking.rescheduled_link}}, {{meeting.title}}, etc.) are template placeholders that would be replaced with actual data during email generation. There is no evidence of unsanitized user input reaching any dangerous sinks. The code contains static HTML templates and configuration arrays, with no user input processing, database queries, file operations, or other security-sensitive operations visible in the diff.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/HostsController.php 2025-11-19 10:50:13.127807624 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/HostsController.php 2025-11-19 10:50:25.778618167 +0000@@ -154,7 +154,7 @@ array( 'methods' => 'GET', 'callback' => array( $this, 'FetchIntegrationSettings' ),- 'permission_callback' => array(new RouteController() , 'permission_callback'),+ 'permission_callback' => array(new RouteController() , 'tfhb_manage_integrations_permission'), ) ); @@ -689,6 +689,56 @@ $mailchimp['connection_status'] = 0; } + // Telegram+ $telegram = isset( $_tfhb_host_integration_settings['telegram'] ) ? $_tfhb_host_integration_settings['telegram'] : array();+ if (isset($_tfhb_integration_settings['telegram']['status']) && $_tfhb_integration_settings['telegram']['status'] == true ) {++ $telegram['type'] = 'telegram';+ $telegram['status'] = $_tfhb_host_integration_settings['telegram']['status'];+ $telegram['connection_status'] = $_tfhb_integration_settings['telegram']['status'];+ $telegram['bot_token'] = $_tfhb_host_integration_settings['telegram']['bot_token'];+ $telegram['chat_id'] = $_tfhb_host_integration_settings['telegram']['chat_id'];++ }else{+ $telegram['type'] = 'telegram';+ $telegram['status'] = 0; + $telegram['connection_status'] = 0; + }++ // twilio+ $twilio = isset( $_tfhb_host_integration_settings['twilio'] ) ? $_tfhb_host_integration_settings['twilio'] : array();+ if (isset($_tfhb_integration_settings['twilio']['status']) && $_tfhb_integration_settings['twilio']['status'] == true ) {++ $twilio['type'] = 'twilio';+ $twilio['status'] = $_tfhb_host_integration_settings['twilio']['status'];+ $twilio['connection_status'] = $_tfhb_integration_settings['twilio']['status'];+ $twilio['receive_number'] = $_tfhb_host_integration_settings['twilio']['receive_number'];+ $twilio['from_number'] = $_tfhb_host_integration_settings['twilio']['from_number'];+ $twilio['sid'] = $_tfhb_host_integration_settings['twilio']['sid'];+ $twilio['token'] = $_tfhb_host_integration_settings['twilio']['token'];+ $twilio['otp_type'] = $_tfhb_host_integration_settings['twilio']['otp_type'];++ }else{+ $twilio['type'] = 'twilio';+ $twilio['status'] = 0; + $twilio['connection_status'] = 0; + }++ // slack+ $slack = isset( $_tfhb_host_integration_settings['slack'] ) ? $_tfhb_host_integration_settings['slack'] : array();+ if (isset($_tfhb_integration_settings['slack']['status']) && $_tfhb_integration_settings['slack']['status'] == true ) {++ $slack['type'] = 'slack';+ $slack['status'] = $_tfhb_host_integration_settings['slack']['status'];+ $slack['connection_status'] = $_tfhb_integration_settings['slack']['status'];+ $slack['endpoint'] = $_tfhb_host_integration_settings['slack']['endpoint'];++ }else{+ $slack['type'] = 'slack';+ $slack['status'] = 0; + $slack['connection_status'] = 0; + }+ // Zoho $zoho = isset( $_tfhb_host_integration_settings['zoho'] ) ? $_tfhb_host_integration_settings['zoho'] : array(); if (isset($_tfhb_integration_settings['zoho']['status']) && $_tfhb_integration_settings['zoho']['status'] ) {@@ -714,10 +764,13 @@ 'status' => true, 'integration_settings' => $_tfhb_host_integration_settings, 'google_calendar' => $google_calendar,- 'zoom_meeting' => $zoom_meeting, + 'zoom_meeting' => $zoom_meeting, 'apple_calendar' => $apple_calendar, 'mailchimp' => $mailchimp, 'zoho' => $zoho,+ 'telegram' => $telegram,+ 'twilio' => $twilio,+ 'slack' => $slack, '_tfhb_integration_settings' => $_tfhb_integration_settings, ); @@ -811,6 +864,41 @@ $responseData['status'] = true; $responseData['message'] = esc_html(__('Mailchimp Settings Updated Successfully', 'hydra-booking')); + } elseif ( $key == 'telegram_data' ) {+ $_tfhb_host_integration_settings['telegram']['type'] = 'telegram';+ $_tfhb_host_integration_settings['telegram']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_host_integration_settings['telegram']['bot_token'] = sanitize_text_field( $data['bot_token'] );+ $_tfhb_host_integration_settings['telegram']['chat_id'] = sanitize_text_field( $data['chat_id'] );++ // update User Meta+ update_user_meta( $user_id, '_tfhb_host_integration_settings', $_tfhb_host_integration_settings );++ $responseData['status'] = true;+ $responseData['message'] = esc_html(__('Telegram Settings Updated Successfully', 'hydra-booking')); + } elseif ( $key == 'twilio_data' ) {+ $_tfhb_host_integration_settings['twilio']['type'] = 'twilio';+ $_tfhb_host_integration_settings['twilio']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_host_integration_settings['twilio']['receive_number'] = sanitize_text_field( $data['receive_number'] );+ $_tfhb_host_integration_settings['twilio']['from_number'] = sanitize_text_field( $data['from_number'] );+ $_tfhb_host_integration_settings['twilio']['sid'] = sanitize_text_field( $data['sid'] );+ $_tfhb_host_integration_settings['twilio']['token'] = sanitize_text_field( $data['token'] );+ $_tfhb_host_integration_settings['twilio']['otp_type'] = sanitize_text_field( $data['otp_type'] );++ // update User Meta+ update_user_meta( $user_id, '_tfhb_host_integration_settings', $_tfhb_host_integration_settings );++ $responseData['status'] = true;+ $responseData['message'] = esc_html(__('Twilio Settings Updated Successfully', 'hydra-booking')); + } elseif ( $key == 'slack_data' ) {+ $_tfhb_host_integration_settings['slack']['type'] = 'slack';+ $_tfhb_host_integration_settings['slack']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_host_integration_settings['slack']['endpoint'] = sanitize_text_field( $data['endpoint'] );++ // update User Meta+ update_user_meta( $user_id, '_tfhb_host_integration_settings', $_tfhb_host_integration_settings );++ $responseData['status'] = true;+ $responseData['message'] = esc_html(__('Slack Settings Updated Successfully', 'hydra-booking')); } elseif ( $key == 'zoho' ) { $_tfhb_host_integration_settings['zoho']['type'] = 'zoho'; $_tfhb_host_integration_settings['zoho']['status'] = sanitize_text_field( $data['status'] );
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - admin/Controller/HostsController.php Lines 867, 878-882, 893-894
Old Code:
```php
$_tfhb_host_integration_settings['telegram']['bot_token'] = sanitize_text_field( $data['bot_token'] );
$_tfhb_host_integration_settings['telegram']['chat_id'] = sanitize_text_field( $data['chat_id'] );
...
$_tfhb_host_integration_settings['twilio']['receive_number'] = sanitize_text_field( $data['receive_number'] );
$_tfhb_host_integration_settings['twilio']['from_number'] = sanitize_text_field( $data['from_number'] );
$_tfhb_host_integration_settings['twilio']['sid'] = sanitize_text_field( $data['sid'] );
$_tfhb_host_integration_settings['twilio']['token'] = sanitize_text_field( $data['token'] );
$_tfhb_host_integration_settings['twilio']['otp_type'] = sanitize_text_field( $data['otp_type'] );
...
$_tfhb_host_integration_settings['slack']['endpoint'] = sanitize_text_field( $data['endpoint'] );
```
Fixed Code:
```php
// Same code - already properly sanitized
```
Explanation:
All user input values (bot_token, chat_id, receive_number, from_number, sid, token, otp_type, endpoint) are passed through sanitize_text_field() before being stored. sanitize_text_field() properly sanitizes the input by removing tags, encoding special characters, and removing line breaks, making it safe from XSS when later output. The data flow shows user input → sanitize_text_field() → storage, breaking any potential XSS vulnerability.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/MeetingController.php 2025-11-19 10:50:13.128807688 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/MeetingController.php 2025-11-19 10:50:25.779618231 +0000@@ -782,6 +782,53 @@ } } + private function ensure_notification_channel_defaults( &$notification, $channel ) {+ // Decode if it's a string+ if ( ! isset( $notification ) || ! is_object( $notification ) ) {+ if ( is_string( $notification ) ) {+ $decoded = json_decode( $notification );+ $notification = ( is_object( $decoded ) || is_array( $decoded ) ) ? (object) $decoded : new \stdClass();+ } else {+ $notification = new \stdClass();+ }+ }+ + // Make sure the channel exists+ if ( ! isset( $notification->$channel ) || ! is_object( $notification->$channel ) ) {+ $notification->$channel = new \stdClass();+ }+ + $default_notification_data = new Helper();+ $_tfhb_default_notification_settings = $default_notification_data->get_default_notification_template(); + + if($channel=='slack' || $channel=='twilio' || $channel=='telegram'){+ $defaultKeys = [+ 'booking_confirmation',+ 'booking_cancel',+ 'booking_reschedule',+ ];+ }else{+ $defaultKeys = [+ 'booking_confirmation',+ 'booking_pending',+ 'booking_cancel',+ 'booking_reschedule',+ 'booking_reminder',+ ];+ }+ + foreach ( $defaultKeys as $key ) {+ if ( ! isset( $notification->{$channel}->$key ) ) {+ $notification->{$channel}->$key = (object) [+ 'status' => 0,+ 'body' => !empty($_tfhb_default_notification_settings[$channel][$key]['body']) ? $_tfhb_default_notification_settings[$channel][$key]['body'] : '',+ 'builder' => '',+ ];+ }+ }+ }+ + // Get Single Meeting public function getMeetingData( $request ) { $id = $request['id'];@@ -822,6 +869,31 @@ } $this->ensureBuilderKeyExists($MeetingData->notification);+ ++ if(is_array( $MeetingData->notification)){+ if(empty($MeetingData->notification['slack'])){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'slack' );+ }+ if(empty($MeetingData->notification['telegram'])){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'telegram' );+ }+ if(empty($MeetingData->notification['twilio'])){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'twilio' );+ }+ }+ if( is_object($MeetingData->notification) ){+ if(empty($MeetingData->notification->slack)){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'slack' );+ }+ if(empty($MeetingData->notification->telegram)){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'telegram' );+ }+ if(empty($MeetingData->notification->twilio)){+ $this->ensure_notification_channel_defaults( $MeetingData->notification, 'twilio' );+ }+ }+ // Integration $_tfhb_integration_settings = !empty(get_option( '_tfhb_integration_settings' )) && get_option( '_tfhb_integration_settings' ) != false ? get_option( '_tfhb_integration_settings' ) : array();@@ -981,6 +1053,62 @@ $zohocrm_Data['status'] = false; } + // Telegram+ if(!empty($_tfhb_host_integration_settings['telegram']) && !empty($_tfhb_host_integration_settings['telegram']['status']) && ! empty( $_tfhb_host_integration_settings['telegram']['bot_token'] ) && ! empty( $_tfhb_host_integration_settings['telegram']['chat_id'] )){+ $telegram_status = ! empty( $_tfhb_host_integration_settings['telegram']['status'] ) ? $_tfhb_host_integration_settings['telegram']['status'] : '';+ $telegram_bot_token = ! empty( $_tfhb_host_integration_settings['telegram']['bot_token'] ) ? $_tfhb_host_integration_settings['telegram']['bot_token'] : '';+ $telegram_chat_id = ! empty( $_tfhb_host_integration_settings['telegram']['chat_id'] ) ? $_tfhb_host_integration_settings['telegram']['chat_id'] : '';+ }else{+ $telegram_status = ! empty( $_tfhb_integration_settings['telegram']['status'] ) ? $_tfhb_integration_settings['telegram']['status'] : '';+ $telegram_bot_token = ! empty( $_tfhb_integration_settings['telegram']['bot_token'] ) ? $_tfhb_integration_settings['telegram']['bot_token'] : '';+ $telegram_chat_id = ! empty( $_tfhb_integration_settings['telegram']['chat_id'] ) ? $_tfhb_integration_settings['telegram']['chat_id'] : '';+ }++ $telegram_Data = array();+ if ( ! empty( $telegram_status ) && ! empty( $telegram_bot_token ) && ! empty( $telegram_chat_id ) ) {+ $telegram_Data['status'] = true;+ } else {+ $telegram_Data['status'] = false;+ }++ // Slack+ if(!empty($_tfhb_host_integration_settings['slack']) && !empty($_tfhb_host_integration_settings['slack']['status'])){+ $slack_status = ! empty( $_tfhb_host_integration_settings['slack']['status'] ) ? $_tfhb_host_integration_settings['slack']['status'] : '';+ $slack_endpoint = ! empty( $_tfhb_host_integration_settings['slack']['endpoint'] ) ? $_tfhb_host_integration_settings['slack']['endpoint'] : '';+ }else{+ $slack_status = ! empty( $_tfhb_integration_settings['slack']['status'] ) ? $_tfhb_integration_settings['slack']['status'] : '';+ $slack_endpoint = ! empty( $_tfhb_integration_settings['slack']['endpoint'] ) ? $_tfhb_integration_settings['slack']['endpoint'] : '';+ }++ $slack_Data = array();+ if ( ! empty( $slack_status ) && ! empty( $slack_endpoint ) ) {+ $slack_Data['status'] = true;+ } else {+ $slack_Data['status'] = false;+ }++ // Twilio+ if(!empty($_tfhb_host_integration_settings['twilio']) && !empty($_tfhb_host_integration_settings['twilio']['status'])){+ $twilio_status = ! empty( $_tfhb_host_integration_settings['twilio']['status'] ) ? $_tfhb_host_integration_settings['twilio']['status'] : '';+ $twilio_receive_number = ! empty( $_tfhb_host_integration_settings['twilio']['receive_number'] ) ? $_tfhb_host_integration_settings['twilio']['receive_number'] : '';+ $twilio_from_number = ! empty( $_tfhb_host_integration_settings['twilio']['from_number'] ) ? $_tfhb_host_integration_settings['twilio']['from_number'] : '';+ $twilio_sid = ! empty( $_tfhb_host_integration_settings['twilio']['sid'] ) ? $_tfhb_host_integration_settings['twilio']['sid'] : '';+ $twilio_token = ! empty( $_tfhb_host_integration_settings['twilio']['token'] ) ? $_tfhb_host_integration_settings['twilio']['token'] : '';+ }else{+ $twilio_status = ! empty( $_tfhb_integration_settings['twilio']['status'] ) ? $_tfhb_integration_settings['twilio']['status'] : '';+ $twilio_receive_number = ! empty( $_tfhb_integration_settings['twilio']['receive_number'] ) ? $_tfhb_integration_settings['twilio']['receive_number'] : '';+ $twilio_from_number = ! empty( $_tfhb_integration_settings['twilio']['from_number'] ) ? $_tfhb_integration_settings['twilio']['from_number'] : '';+ $twilio_sid = ! empty( $_tfhb_integration_settings['twilio']['sid'] ) ? $_tfhb_integration_settings['twilio']['sid'] : '';+ $twilio_token = ! empty( $_tfhb_integration_settings['twilio']['token'] ) ? $_tfhb_integration_settings['twilio']['token'] : '';+ }++ $twilio_Data = array();+ if ( ! empty( $twilio_status ) && ! empty( $twilio_receive_number ) && ! empty( $twilio_from_number ) && ! empty( $twilio_sid ) && ! empty( $twilio_token ) ) {+ $twilio_Data['status'] = true;+ } else {+ $twilio_Data['status'] = false;+ }+ // Fetch Questions Data $questions_form_type = ! empty( $MeetingData->questions_form_type ) ? $MeetingData->questions_form_type : ''; $questions_form = ! empty( $MeetingData->questions_form ) ? $MeetingData->questions_form : 0;@@ -1007,6 +1135,9 @@ 'zohocrm' => $zohocrm_Data, 'formsList' => $formsList, 'integrations' => $integrations,+ 'telegram' => $telegram_Data,+ 'slack' => $slack_Data,+ 'twilio' => $twilio_Data, 'message' => __( 'Meeting Data','hydra-booking' ), ); return rest_ensure_response( $data );
Vulnerability Existed: no
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor - CWE-200 - admin/Controller/MeetingController.php [1053-1115]
Old Code:
```php
// Telegram
if(!empty($_tfhb_host_integration_settings['telegram']) && !empty($_tfhb_host_integration_settings['telegram']['status']) && ! empty( $_tfhb_host_integration_settings['telegram']['bot_token'] ) && ! empty( $_tfhb_host_integration_settings['telegram']['chat_id'] )){
$telegram_status = ! empty( $_tfhb_host_integration_settings['telegram']['status'] ) ? $_tfhb_host_integration_settings['telegram']['status'] : '';
$telegram_bot_token = ! empty( $_tfhb_host_integration_settings['telegram']['bot_token'] ) ? $_tfhb_host_integration_settings['telegram']['bot_token'] : '';
$telegram_chat_id = ! empty( $_tfhb_host_integration_settings['telegram']['chat_id'] ) ? $_tfhb_host_integration_settings['telegram']['chat_id'] : '';
}else{
$telegram_status = ! empty( $_tfhb_integration_settings['telegram']['status'] ) ? $_tfhb_integration_settings['telegram']['status'] : '';
$telegram_bot_token = ! empty( $_tfhb_integration_settings['telegram']['bot_token'] ) ? $_tfhb_integration_settings['telegram']['bot_token'] : '';
$telegram_chat_id = ! empty( $_tfhb_integration_settings['telegram']['chat_id'] ) ? $_tfhb_integration_settings['telegram']['chat_id'] : '';
}
// ... similar code for Slack and Twilio ...
$data = array(
// ... other data ...
'telegram' => $telegram_Data,
'slack' => $slack_Data,
'twilio' => $twilio_Data,
);
```
Fixed Code:
```php
// The code remains the same - no sensitive data is exposed in the response
```
Explanation:
The code retrieves Telegram, Slack, and Twilio integration settings from WordPress options, but only returns status flags (true/false) in the API response. Sensitive data like bot tokens, chat IDs, API keys, and tokens are stored in local variables but are NOT included in the final response array. The response only contains boolean status indicators, not the actual sensitive credentials.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/SettingsController.php 2025-11-19 10:50:13.129807752 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/SettingsController.php 2025-11-19 10:50:25.780618295 +0000@@ -598,7 +598,57 @@ 'message' => __('Paypal Settings Updated Successfully', 'hydra-booking') ); return rest_ensure_response( $data );- }elseif ( $key == 'webhook' ) {+ } elseif ( $key == 'telegram_data' ) {+ $_tfhb_integration_settings['telegram']['type'] = sanitize_text_field( $data['type'] );+ $_tfhb_integration_settings['telegram']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_integration_settings['telegram']['bot_token'] = sanitize_text_field( $data['bot_token'] );+ $_tfhb_integration_settings['telegram']['chat_id'] = sanitize_text_field( $data['chat_id'] );++ // update option+ update_option( '_tfhb_integration_settings', $_tfhb_integration_settings );+ $option = get_option( '_tfhb_integration_settings', $_tfhb_integration_settings );++ $data = array(+ 'status' => true,+ 'integration_settings' => $option,+ 'message' => __('Telegram Settings Updated Successfully', 'hydra-booking')+ );+ return rest_ensure_response( $data );+ } elseif ( $key == 'twilio_data' ) {+ $_tfhb_integration_settings['twilio']['type'] = sanitize_text_field( $data['type'] );+ $_tfhb_integration_settings['twilio']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_integration_settings['twilio']['receive_number'] = sanitize_text_field( $data['receive_number'] );+ $_tfhb_integration_settings['twilio']['from_number'] = sanitize_text_field( $data['from_number'] );+ $_tfhb_integration_settings['twilio']['sid'] = sanitize_text_field( $data['sid'] );+ $_tfhb_integration_settings['twilio']['token'] = sanitize_text_field( $data['token'] );+ $_tfhb_integration_settings['twilio']['otp_type'] = sanitize_text_field( $data['otp_type'] );++ // update option+ update_option( '_tfhb_integration_settings', $_tfhb_integration_settings );+ $option = get_option( '_tfhb_integration_settings', $_tfhb_integration_settings );++ $data = array(+ 'status' => true,+ 'integration_settings' => $option,+ 'message' => __('Twilio Settings Updated Successfully', 'hydra-booking')+ );+ return rest_ensure_response( $data );+ } elseif ( $key == 'slack_data' ) {+ $_tfhb_integration_settings['slack']['type'] = sanitize_text_field( $data['type'] );+ $_tfhb_integration_settings['slack']['status'] = sanitize_text_field( $data['status'] );+ $_tfhb_integration_settings['slack']['endpoint'] = sanitize_text_field( $data['endpoint'] );++ // update option+ update_option( '_tfhb_integration_settings', $_tfhb_integration_settings );+ $option = get_option( '_tfhb_integration_settings', $_tfhb_integration_settings );++ $data = array(+ 'status' => true,+ 'integration_settings' => $option,+ 'message' => __('Slack Settings Updated Successfully', 'hydra-booking')+ );+ return rest_ensure_response( $data );+ } elseif ( $key == 'webhook' ) { $_tfhb_integration_settings['webhook']['status'] = sanitize_text_field( $data['status'] ); @@ -771,13 +821,65 @@ if(empty($_tfhb_notification_settings)){ $default_notification = new Helper(); $_tfhb_notification_settings = $default_notification->get_default_notification_template(); + }else{+ $default_notification = new Helper();+ $_tfhb_default_notification_settings = $default_notification->get_default_notification_template(); + if(empty($_tfhb_notification_settings['telegram'])){+ $_tfhb_notification_settings['telegram'] = !empty($_tfhb_default_notification_settings['telegram']) ? $_tfhb_default_notification_settings['telegram'] : '';+ }+ if(empty($_tfhb_notification_settings['twilio'])){+ $_tfhb_notification_settings['twilio'] = !empty($_tfhb_default_notification_settings['twilio']) ? $_tfhb_default_notification_settings['twilio'] : '';+ }+ if(empty($_tfhb_notification_settings['slack'])){+ $_tfhb_notification_settings['slack'] = !empty($_tfhb_default_notification_settings['slack']) ? $_tfhb_default_notification_settings['slack'] : '';+ } } $this->ensureBuilderKeyExists($_tfhb_notification_settings); + $_tfhb_integration_settings = !empty(get_option( '_tfhb_integration_settings' )) && get_option( '_tfhb_integration_settings' ) != false ? get_option( '_tfhb_integration_settings' ) : array();++ // Telegram+ $telegram_status = ! empty( $_tfhb_integration_settings['telegram']['status'] ) ? $_tfhb_integration_settings['telegram']['status'] : '';+ $telegram_bot_token = ! empty( $_tfhb_integration_settings['telegram']['bot_token'] ) ? $_tfhb_integration_settings['telegram']['bot_token'] : '';+ $telegram_chat_id = ! empty( $_tfhb_integration_settings['telegram']['chat_id'] ) ? $_tfhb_integration_settings['telegram']['chat_id'] : '';+ $telegram_Data = array();+ if ( ! empty( $telegram_status ) && ! empty( $telegram_bot_token ) && ! empty( $telegram_chat_id ) ) {+ $telegram_Data['status'] = true;+ } else {+ $telegram_Data['status'] = false;+ }++ // Slack+ $slack_status = ! empty( $_tfhb_integration_settings['slack']['status'] ) ? $_tfhb_integration_settings['slack']['status'] : '';+ $slack_endpoint = ! empty( $_tfhb_integration_settings['slack']['endpoint'] ) ? $_tfhb_integration_settings['slack']['endpoint'] : '';+ $slack_Data = array();+ if ( ! empty( $slack_status ) && ! empty( $slack_endpoint ) ) {+ $slack_Data['status'] = true;+ } else {+ $slack_Data['status'] = false;+ }++ // Twilio+ $twilio_status = ! empty( $_tfhb_integration_settings['twilio']['status'] ) ? $_tfhb_integration_settings['twilio']['status'] : '';+ $twilio_receive_number = ! empty( $_tfhb_integration_settings['twilio']['receive_number'] ) ? $_tfhb_integration_settings['twilio']['receive_number'] : '';+ $twilio_from_number = ! empty( $_tfhb_integration_settings['twilio']['from_number'] ) ? $_tfhb_integration_settings['twilio']['from_number'] : '';+ $twilio_sid = ! empty( $_tfhb_integration_settings['twilio']['sid'] ) ? $_tfhb_integration_settings['twilio']['sid'] : '';+ $twilio_token = ! empty( $_tfhb_integration_settings['twilio']['token'] ) ? $_tfhb_integration_settings['twilio']['token'] : '';++ $twilio_Data = array();+ if ( ! empty( $twilio_status ) && ! empty( $twilio_receive_number ) && ! empty( $twilio_from_number ) && ! empty( $twilio_sid ) && ! empty( $twilio_token ) ) {+ $twilio_Data['status'] = true;+ } else {+ $twilio_Data['status'] = false;+ }+ $data = array( 'status' => true, 'notification_settings' => $_tfhb_notification_settings,+ 'telegram' => $telegram_Data,+ 'slack' => $slack_Data,+ 'twilio' => $twilio_Data, ); return rest_ensure_response( $data ); }@@ -812,6 +914,33 @@ } } + // sanitize Telegram Notification+ if ( isset( $request['telegram'] ) ) {+ foreach ( $request['telegram'] as $key => $value ) {+ $data['telegram'][ $key ]['status'] = sanitize_text_field( $value['status'] );+ $data['telegram'][ $key ]['body'] = wp_kses_post( $value['body'] );+ $data['telegram'][ $key ]['builder'] = $value['builder'];+ }+ }++ // Sanitize Twilio Notification+ if ( isset( $request['twilio'] ) ) {+ foreach ( $request['twilio'] as $key => $value ) {+ $data['twilio'][ $key ]['status'] = sanitize_text_field( $value['status'] );+ $data['twilio'][ $key ]['body'] = wp_kses_post( $value['body'] );+ $data['twilio'][ $key ]['builder'] = $value['builder'];+ }+ }++ // Sanitize Slack Notification+ if ( isset( $request['slack'] ) ) {+ foreach ( $request['slack'] as $key => $value ) {+ $data['slack'][ $key ]['status'] = sanitize_text_field( $value['status'] );+ $data['slack'][ $key ]['body'] = wp_kses_post( $value['body'] );+ $data['slack'][ $key ]['builder'] = $value['builder'];+ }+ }+ // update option update_option( '_tfhb_notification_settings', $data );
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - admin/Controller/SettingsController.php [917-919, 927-929, 935-937]
Old Code:
```php
$data['telegram'][ $key ]['builder'] = $value['builder'];
$data['twilio'][ $key ]['builder'] = $value['builder'];
$data['slack'][ $key ]['builder'] = $value['builder'];
```
Fixed Code:
```php
$data['telegram'][ $key ]['builder'] = wp_kses_post( $value['builder'] );
$data['twilio'][ $key ]['builder'] = wp_kses_post( $value['builder'] );
$data['slack'][ $key ]['builder'] = wp_kses_post( $value['builder'] );
```
Explanation:
The code assigns `$value['builder']` directly to the notification settings array without sanitization. However, this data is stored in the WordPress options table via `update_option()` and later retrieved for display. Since the code does not show how this data is rendered, and there is no evidence of unsanitized output to the browser, I cannot confirm that attacker-controlled data reaches an HTML output sink unsanitized. The vulnerability status is "no" because I cannot trace the complete flow to an exploitable XSS sink.
Vulnerability Existed: no
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor - admin/Controller/SettingsController.php [843-847, 855-859, 867-871]
Old Code:
```php
$data = array(
'status' => true,
'notification_settings' => $_tfhb_notification_settings,
'telegram' => $telegram_Data,
'slack' => $slack_Data,
'twilio' => $twilio_Data,
);
```
Fixed Code:
```php
// No change needed - this is information disclosure via API response, not a code vulnerability
```
Explanation:
The code returns integration status information (telegram, slack, twilio configuration status) in an API response. While this could reveal system configuration details to authenticated users, this is an information disclosure issue rather than a code vulnerability. The response is properly structured and doesn't expose actual credentials - only configuration status.
Vulnerability Existed: no
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') - admin/Controller/SettingsController.php [600-604, 616-622, 634-636]
Old Code:
```php
$_tfhb_integration_settings['telegram']['bot_token'] = sanitize_text_field( $data['bot_token'] );
$_tfhb_integration_settings['twilio']['sid'] = sanitize_text_field( $data['sid'] );
$_tfhb_integration_settings['twilio']['token'] = sanitize_text_field( $data['token'] );
```
Fixed Code:
```php
// No change needed - data is properly sanitized for storage
```
Explanation:
All user input for integration settings (telegram bot_token, twilio sid/token, slack endpoint) is properly sanitized using `sanitize_text_field()` before being stored via `update_option()`. The WordPress `update_option()` function uses prepared statements internally, preventing SQL injection. The data flow is: user input → sanitize_text_field() → update_option() (with prepared statements) → safe storage.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/admin/Controller/TransStrings.php 2025-11-19 10:50:13.129807752 +0000+++ cache/hydra-booking_1.1.11/admin/Controller/TransStrings.php 2025-11-19 10:50:25.781618359 +0000@@ -606,6 +606,39 @@ 'Enter Your App Client ID' => __('Enter Your App Client ID', 'hydra-booking'), 'Zoom App Secret Key' => __('Zoom App Secret Key', 'hydra-booking'), 'Enter Your App Secret Key' => __('Enter Your App Secret Key', 'hydra-booking'), + 'Telegram' => __('Telegram', 'hydra-booking'),+ 'Connect Telegram API to configure virtual meetings.' => __('Connect Telegram API to configure virtual meetings.', 'hydra-booking'),+ 'Add New Telegram Option' => __('Add New Telegram Option', 'hydra-booking'),+ 'Please read the documentation here for step by step guide to know how you can get BOT Token and Chat ID from Telegram Account' => __('Please read the documentation here for step by step guide to know how you can get BOT Token and Chat ID from Telegram Account', 'hydra-booking'),+ 'Telegram BOT Token' => __('Telegram BOT Token', 'hydra-booking'),+ 'Enter Your Telegram BOT Token' => __('Enter Your Telegram BOT Token', 'hydra-booking'),+ 'Telegram Chat ID' => __('Telegram Chat ID', 'hydra-booking'),+ 'Enter Your Telegram Chat ID' => __('Enter Your Telegram Chat ID', 'hydra-booking'),+ 'Whatsapp' => __('Whatsapp', 'hydra-booking'),+ 'Connect Whatsapp API to configure virtual meetings.' => __('Connect Whatsapp API to configure virtual meetings.', 'hydra-booking'),+ 'Add Whatsapp Option' => __('Add Whatsapp Option', 'hydra-booking'),+ 'Please read the documentation here for step by step guide to know how you can get Access Token from Whatsapp Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Whatsapp Account', 'hydra-booking'),+ 'Whatsapp Number' => __('Whatsapp Number', 'hydra-booking'),+ 'Enter Your Whatsapp Number' => __('Enter Your Whatsapp Number', 'hydra-booking'),+ 'Access Token' => __('Access Token', 'hydra-booking'),+ 'Enter Your Access Token' => __('Enter Your Access Token', 'hydra-booking'),+ 'Twilio' => __('Twilio', 'hydra-booking'),+ 'Connect Twilio API to configure virtual meetings.' => __('Connect Twilio API to configure virtual meetings.', 'hydra-booking'),+ 'Add Twilio Option' => __('Add Twilio Option', 'hydra-booking'),+ 'Please read the documentation here for step by step guide to know how you can get Access Token from Twilio Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Twilio Account', 'hydra-booking'),+ 'Account SID' => __('Account SID', 'hydra-booking'),+ 'Enter Your Account SID' => __('Enter Your Account SID', 'hydra-booking'),+ 'From Number' => __('From Number', 'hydra-booking'),+ 'Enter Your From Number' => __('Enter Your From Number', 'hydra-booking'),+ 'Receiver Number' => __('Receiver Number', 'hydra-booking'),+ 'Enter Your Receiver Number' => __('Enter Your Receiver Number', 'hydra-booking'),+ 'Slack' => __('Slack', 'hydra-booking'),+ 'Connect Slack API to configure virtual meetings.' => __('Connect Slack API to configure virtual meetings.', 'hydra-booking'),+ 'Add Slack Option' => __('Add Slack Option', 'hydra-booking'),+ 'Please read the documentation here for step by step guide to know how you can get Access Token from Slack Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Slack Account', 'hydra-booking'),+ 'Channel Name' => __('Channel Name', 'hydra-booking'),+ 'Enter Your Channel Name' => __('Enter Your Channel Name', 'hydra-booking'),+ // Component : meetings 'Integration' => __('Integration', 'hydra-booking'),
Vulnerability Existed: no
No vulnerability - N/A - admin/Controller/TransStrings.php [606-644]
Old Code:
```php
// No old code for these specific lines as they are additions
```
Fixed Code:
```php
'Telegram' => __('Telegram', 'hydra-booking'),
'Connect Telegram API to configure virtual meetings.' => __('Connect Telegram API to configure virtual meetings.', 'hydra-booking'),
'Add New Telegram Option' => __('Add New Telegram Option', 'hydra-booking'),
'Please read the documentation here for step by step guide to know how you can get BOT Token and Chat ID from Telegram Account' => __('Please read the documentation here for step by step guide to know how you can get BOT Token and Chat ID from Telegram Account', 'hydra-booking'),
'Telegram BOT Token' => __('Telegram BOT Token', 'hydra-booking'),
'Enter Your Telegram BOT Token' => __('Enter Your Telegram BOT Token', 'hydra-booking'),
'Telegram Chat ID' => __('Telegram Chat ID', 'hydra-booking'),
'Enter Your Telegram Chat ID' => __('Enter Your Telegram Chat ID', 'hydra-booking'),
'Whatsapp' => __('Whatsapp', 'hydra-booking'),
'Connect Whatsapp API to configure virtual meetings.' => __('Connect Whatsapp API to configure virtual meetings.', 'hydra-booking'),
'Add Whatsapp Option' => __('Add Whatsapp Option', 'hydra-booking'),
'Please read the documentation here for step by step guide to know how you can get Access Token from Whatsapp Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Whatsapp Account', 'hydra-booking'),
'Whatsapp Number' => __('Whatsapp Number', 'hydra-booking'),
'Enter Your Whatsapp Number' => __('Enter Your Whatsapp Number', 'hydra-booking'),
'Access Token' => __('Access Token', 'hydra-booking'),
'Enter Your Access Token' => __('Enter Your Access Token', 'hydra-booking'),
'Twilio' => __('Twilio', 'hydra-booking'),
'Connect Twilio API to configure virtual meetings.' => __('Connect Twilio API to configure virtual meetings.', 'hydra-booking'),
'Add Twilio Option' => __('Add Twilio Option', 'hydra-booking'),
'Please read the documentation here for step by step guide to know how you can get Access Token from Twilio Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Twilio Account', 'hydra-booking'),
'Account SID' => __('Account SID', 'hydra-booking'),
'Enter Your Account SID' => __('Enter Your Account SID', 'hydra-booking'),
'From Number' => __('From Number', 'hydra-booking'),
'Enter Your From Number' => __('Enter Your From Number', 'hydra-booking'),
'Receiver Number' => __('Receiver Number', 'hydra-booking'),
'Enter Your Receiver Number' => __('Enter Your Receiver Number', 'hydra-booking'),
'Slack' => __('Slack', 'hydra-booking'),
'Connect Slack API to configure virtual meetings.' => __('Connect Slack API to configure virtual meetings.', 'hydra-booking'),
'Add Slack Option' => __('Add Slack Option', 'hydra-booking'),
'Please read the documentation here for step by step guide to know how you can get Access Token from Slack Account' => __('Please read the documentation here for step by step guide to know how you can get Access Token from Slack Account', 'hydra-booking'),
'Channel Name' => __('Channel Name', 'hydra-booking'),
'Enter Your Channel Name' => __('Enter Your Channel Name', 'hydra-booking'),
```
Explanation:
This diff only adds new translation strings to the translation file. These are static string definitions that map English text to localized versions using WordPress's __() function. There are no user inputs, no data processing, no database operations, and no security-sensitive operations in this code. The changes are purely for internationalization purposes and do not introduce any security vulnerabilities.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Archive/archive-page-tfhb-host.php 2025-11-19 10:50:13.130807816 +0000+++ cache/hydra-booking_1.1.11/app/Content/Archive/archive-page-tfhb-host.php 2025-11-19 10:50:25.781618359 +0000@@ -3,7 +3,7 @@ // exit if ( ! defined( 'ABSPATH' ) ) { exit; } use HydraBooking\DB\Meeting;-+use HydraBooking\Admin\Controller\TransStrings; use HydraBooking\DB\Host; // Get the "username" query variable from the URL $username = get_query_var('username');@@ -66,7 +66,7 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clock"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> - <?php echo esc_html($meeting->duration) ?> minutes+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?> </span> <!-- <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-presentation"><path d="M2 3h20"/><path d="M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3"/><path d="m7 21 5-5 5 5"/></svg> @@ -74,20 +74,20 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-banknote"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg> - <?php echo esc_html($price) ?>+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($price)) ?> </span> </div> </div> </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a> </div> </div> <?php endforeach; else: ?> <div class="tfhb-meeting-list__wrap__no-found">- <p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>+ <p><?php echo esc_html__('No meetings found.', 'hydra_booking')?></p> </div> <?php endif;?>
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - app/Content/Archive/archive-page-tfhb-host.php [66,74,81,87]
Old Code:
```php
<?php echo esc_html($meeting->duration) ?> minutes
<?php echo esc_html($price) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>
<p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>
```
Fixed Code:
```php
<?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?>
<?php echo esc_html(TransStrings::tfhbTranslateNumber($price)) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a>
<p><?php echo esc_html__('No meetings found.', 'hydra_booking')?></p>
```
Explanation:
All user-controlled data is properly escaped using WordPress security functions. The changes involve:
1. Line 66: $meeting->duration is passed through TransStrings::tfhbTranslateNumber() then escaped with esc_html()
2. Line 74: $price is passed through TransStrings::tfhbTranslateNumber() then escaped with esc_html()
3. Line 81: $permalink is properly escaped with esc_url() in href attribute
4. Line 87: Static string is properly escaped with esc_html__()
All output is properly sanitized using WordPress escaping functions, preventing XSS vulnerabilities.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Archive/archive-tfhb_meeting.php 2025-11-19 10:50:13.130807816 +0000+++ cache/hydra-booking_1.1.11/app/Content/Archive/archive-tfhb_meeting.php 2025-11-19 10:50:25.782618423 +0000@@ -3,7 +3,7 @@ // exit if ( ! defined( 'ABSPATH' ) ) { exit; } use HydraBooking\DB\Meeting;- +use HydraBooking\Admin\Controller\TransStrings; $meeting = new Meeting(); $query = array( ); $meetings = $meeting->getAll( $query, 'id', 'DESC');@@ -55,7 +55,7 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clock"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> - <?php echo esc_html($meeting->duration) ?> minutes+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?> </span> <!-- <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-presentation"><path d="M2 3h20"/><path d="M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3"/><path d="m7 21 5-5 5 5"/></svg> @@ -63,20 +63,20 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-banknote"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg> - <?php echo esc_html($price) ?>+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->price)) ?> </span> </div> </div> </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a> </div> </div> <?php endforeach; else: ?> <div class="tfhb-meeting-list__wrap__no-found">- <p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>+ <p><?php echo esc_html__('No meetings found.', 'hydra_booking')?></p> </div> <?php endif;?>
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - app/Content/Archive/archive-tfhb_meeting.php [55,63,70,75]
Old Code:
```php
<?php echo esc_html($meeting->duration) ?> minutes
<?php echo esc_html($price) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>
<p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>
```
Fixed Code:
```php
<?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?>
<?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->price)) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a>
<p><?php echo esc_html__('No meetings found.', 'hydra_booking')?></p>
```
Explanation:
The changes are localization improvements, not security fixes. All user-controlled data is properly escaped:
- $meeting->duration and $meeting->price are passed through TransStrings::tfhbTranslateNumber() then esc_html()
- $permalink is passed through esc_url() for URL context
- Text strings are properly localized using esc_html__() with escaping
The original code already used proper escaping functions (esc_html, esc_url), so no XSS vulnerability existed before or after the changes.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Archive/taxonomy-meeting_category.php 2025-11-19 10:50:13.131807880 +0000+++ cache/hydra-booking_1.1.11/app/Content/Archive/taxonomy-meeting_category.php 2025-11-19 10:50:25.782618423 +0000@@ -3,7 +3,7 @@ // exit if ( ! defined( 'ABSPATH' ) ) { exit; } use HydraBooking\DB\Meeting;-+use HydraBooking\Admin\Controller\TransStrings; $page_id = get_queried_object_id(); $meeting = new Meeting(); $query = array( );@@ -58,7 +58,7 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clock"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> - <?php echo esc_html($meeting->duration) ?> minutes+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?> </span> <!-- <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-presentation"><path d="M2 3h20"/><path d="M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3"/><path d="m7 21 5-5 5 5"/></svg> @@ -66,20 +66,20 @@ </span> --> <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-banknote"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg> - <?php echo esc_html($price) ?>+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->price)) ?> </span> </div> </div> </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a> </div> </div> <?php endforeach; else: ?> <div class="tfhb-meeting-list__wrap__no-found">- <p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>+ <p><?php esc_html__('No meetings found.', 'hydra_booking')?></p> </div> <?php endif;?>
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - app/Content/Archive/taxonomy-meeting_category.php [58,66,73,77]
Old Code:
```php
<?php echo esc_html($meeting->duration) ?> minutes
<?php echo esc_html($price) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>
<p><?php esc_html_e('No meetings found.', 'hydra_booking')?></p>
```
Fixed Code:
```php
<?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html__('minutes', 'hydra_booking')?>
<?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->price)) ?>
<a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html__('Select', 'hydra_booking')?></a>
<p><?php esc_html__('No meetings found.', 'hydra_booking')?></p>
```
Explanation:
The changes involve internationalization improvements and do not introduce XSS vulnerabilities. All user-facing strings are properly escaped:
- Line 58: $meeting->duration is passed through TransStrings::tfhbTranslateNumber() and then esc_html()
- Line 66: $meeting->price is passed through TransStrings::tfhbTranslateNumber() and then esc_html()
- Line 73: $permalink uses esc_url() for URL context
- Line 77: Static string uses esc_html__() for translation
All output is properly contextualized and escaped, preventing XSS vulnerabilities.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Template/meeting-cencel.php 2025-11-19 10:50:13.131807880 +0000+++ cache/hydra-booking_1.1.11/app/Content/Template/meeting-cencel.php 2025-11-19 10:50:25.782618423 +0000@@ -92,7 +92,7 @@ <?php if ( $data->status == 'canceled' ) : ?> <div class="tfhb-notice notice-error" > - <span><?php echo esc_html( 'This meeting has been cancelled by the ' ) . esc_attr($data->cancelled_by) . '.'; ?></span>+ <span><?php echo esc_html_( 'This meeting has been cancelled by the ', 'hydra-booking' ) . esc_attr($data->cancelled_by) . '.'; ?></span> </div> <?php else : ?> <div class="hidden-field">
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - app/Content/Template/meeting-cencel.php [92]
Old Code:
```php
<span><?php echo esc_html( 'This meeting has been cancelled by the ' ) . esc_attr($data->cancelled_by) . '.'; ?></span>
```
Fixed Code:
```php
<span><?php echo esc_html_( 'This meeting has been cancelled by the ', 'hydra-booking' ) . esc_attr($data->cancelled_by) . '.'; ?></span>
```
Explanation:
The change only modifies the internationalization function call from `esc_html()` to `esc_html_()` with added text domain. The user-controlled value `$data->cancelled_by` continues to be properly escaped with `esc_attr()` in both versions. The output context is HTML attribute context (inside a `<span>` element), and `esc_attr()` provides appropriate encoding for this context. There is no XSS vulnerability in either version because the user input is properly escaped.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Template/meeting-confirmation.php 2025-11-19 10:50:13.131807880 +0000+++ cache/hydra-booking_1.1.11/app/Content/Template/meeting-confirmation.php 2025-11-19 10:50:25.782618423 +0000@@ -159,7 +159,7 @@ ), home_url() );- echo '<a href="' . esc_attr( $cancel ) . '">Cancel booking</a>';+ echo '<a href="' . esc_attr( $cancel ) . '">'.esc_html__('Cancel booking', 'hydra_booking').'</a>'; } if ( true == $data->attendee_can_reschedule ) { @@ -173,7 +173,7 @@ home_url() ); - echo '<a href="' . esc_url( $reschedule_url ) . '">Reschedule</a>';+ echo '<a href="' . esc_url( $reschedule_url ) . '">'.esc_html__('Reschedule', 'hydra_booking').'</a>'; } ?> </div>
Vulnerability Existed: no
Cross-site Scripting (XSS) - CWE-79 - app/Content/Template/meeting-confirmation.php [Lines 159,173]
Old Code:
```php
echo '<a href="' . esc_attr( $cancel ) . '">Cancel booking</a>';
echo '<a href="' . esc_url( $reschedule_url ) . '">Reschedule</a>';
```
Fixed Code:
```php
echo '<a href="' . esc_attr( $cancel ) . '">'.esc_html__('Cancel booking', 'hydra_booking').'</a>';
echo '<a href="' . esc_url( $reschedule_url ) . '">'.esc_html__('Reschedule', 'hydra_booking').'</a>';
```
Explanation:
The diff shows internationalization hardening, not security fixes. The original code already used proper escaping:
- `$cancel` was output with `esc_attr()` in href attribute context
- `$reschedule_url` was output with `esc_url()` in href attribute context
- Link text was hardcoded English strings, not user input
The change replaces hardcoded text with translated strings via `esc_html__()`, which escapes HTML special characters. No user-controlled data reaches output unsanitized in either version.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Content/Template/meeting-info.php 2025-11-19 10:50:13.132807944 +0000+++ cache/hydra-booking_1.1.11/app/Content/Template/meeting-info.php 2025-11-19 10:50:25.783618487 +0000@@ -128,7 +128,8 @@ </defs> </svg> </div>- <?php echo ! empty( $meeting['duration'] ) ? esc_html( TransStrings::tfhbTranslateNumber($meeting['duration']) . ' minutes' ) : '0 minutes'; ?>+ <?php echo ! empty( $meeting['duration'] ) ? esc_html( TransStrings::tfhbTranslateNumber($meeting['duration']) . ' ' ) : '0 ' ; ?> + <?php echo esc_html__('minutes', 'hydra-booking') ?> </li> <?php
Vulnerability Existed: no
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - CWE-79 - app/Content/Template/meeting-info.php [128-129]
Old Code:
```php
<?php echo ! empty( $meeting['duration'] ) ? esc_html( TransStrings::tfhbTranslateNumber($meeting['duration']) . ' minutes' ) : '0 minutes'; ?>
```
Fixed Code:
```php
<?php echo ! empty( $meeting['duration'] ) ? esc_html( TransStrings::tfhbTranslateNumber($meeting['duration']) . ' ' ) : '0 ' ; ?>
<?php echo esc_html__('minutes', 'hydra-booking') ?>
```
Explanation:
The original code already used `esc_html()` to escape the dynamic content (`$meeting['duration']` and the string concatenation). The change splits the static string "minutes" into a separate translation call with its own escaping via `esc_html__()`. Both versions properly escape all dynamic content before output. The user-controlled value `$meeting['duration']` passes through `TransStrings::tfhbTranslateNumber()` and then `esc_html()`, ensuring it's safely encoded for HTML context. No XSS vulnerability exists in either version.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/FrontendDashboard/FrontendDashboard.php 2025-11-19 10:50:13.133808009 +0000+++ cache/hydra-booking_1.1.11/app/FrontendDashboard/FrontendDashboard.php 2025-11-19 10:50:25.784618551 +0000@@ -174,7 +174,7 @@ $required_fields = array( 'tfhb_forgot_user'); // Check nonce security if ( ! isset( $_POST['tfhb_forgot_nonce'] ) || ! wp_verify_nonce( $_POST['tfhb_forgot_nonce'], 'tfhb_check_forgot_nonce' ) ) {- $response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'tourfic' );+ $response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'hydra-booking' ); } else { foreach ( $required_fields as $required_field ) {@@ -302,7 +302,10 @@ reset_password( $user, $field['tfhb_password'] ); $response['success'] = true;- $response['message'] = esc_html__( 'Password changed successfully. you can <a href="' . get_permalink( $login_page_id ) . '">login here</a>', 'hydra-booking' );+ $response['message'] = sprintf(+ __( 'Password changed successfully. You can <a href="%s">login here</a>.', 'hydra-booking' ),+ get_permalink( $login_page_id )+ ); } else { $response['message'] = esc_html__( 'User not found', 'hydra-booking' ); }@@ -353,7 +356,7 @@ exit; // Prevent further script execution after redirection } else { // Handle the case where the login page URL is not set- wp_die('Login page URL not found. Please configure the settings.');+ wp_die( __( 'Login page URL not found. Please configure the settings.', 'hydra-booking' ) ); } }@@ -380,22 +383,22 @@ $pages = array( 'login' => array(- 'name' => _x( 'hydra-login', 'Page slug', 'tourfic' ),- 'title' => _x( 'Hydra Login', 'Page title', 'tourfic' ),+ 'name' => _x( 'hydra-login', 'Page slug', 'hydra-booking' ),+ 'title' => _x( 'Hydra Login', 'Page title', 'hydra-booking' ), 'template' => 'tfhb-frontend-login.php', 'content' => '', 'pro' => false, ), 'register' => array(- 'name' => _x( 'hydra-register', 'Page slug', 'tourfic' ),- 'title' => _x( 'Hydra Register', 'Page title', 'tourfic' ),+ 'name' => _x( 'hydra-register', 'Page slug', 'hydra-booking' ),+ 'title' => _x( 'Hydra Register', 'Page title', 'hydra-booking' ), 'template' => 'tfhb-frontend-signup.php', 'content' => '', 'pro' => false, ), 'dashboard' => array(- 'name' => _x( 'hydra-dashboard', 'Page slug', 'tourfic' ),- 'title' => _x( 'Hydra Dashboard', 'Page title', 'tourfic' ),+ 'name' => _x( 'hydra-dashboard', 'Page slug', 'hydra-booking' ),+ 'title' => _x( 'Hydra Dashboard', 'Page title', 'hydra-booking' ), 'template' => 'tfhb-frontend-dashboard.php', 'content' => '', 'pro' => false,
Vulnerability Existed: no
Cross-Site Scripting (XSS) - CWE-79 - app/FrontendDashboard/FrontendDashboard.php 174-302
Old Code:
```php
$response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'tourfic' );
```
Fixed Code:
```php
$response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'hydra-booking' );
```
Explanation:
The change only modifies the text domain from 'tourfic' to 'hydra-booking' for internationalization purposes. The output is still properly escaped using esc_html__(), which prevents XSS vulnerabilities. No user input flows into this message, and the escaping remains intact.
Vulnerability Existed: no
Cross-Site Scripting (XSS) - CWE-79 - app/FrontendDashboard/FrontendDashboard.php 302-310
Old Code:
```php
$response['message'] = esc_html__( 'Password changed successfully. you can <a href="' . get_permalink( $login_page_id ) . '">login here</a>', 'hydra-booking' );
```
Fixed Code:
```php
$response['message'] = sprintf(
__( 'Password changed successfully. You can <a href="%s">login here</a>.', 'hydra-booking' ),
get_permalink( $login_page_id )
);
```
Explanation:
The old code used esc_html__() which would escape HTML tags, breaking the link. The new code uses sprintf() with __() (no escaping) but get_permalink() returns a safe URL from WordPress. The HTML anchor tag is hardcoded, and the URL comes from get_permalink() which is trusted WordPress core functionality. No user input reaches this output.
Vulnerability Existed: no
Cross-Site Scripting (XSS) - CWE-79 - app/FrontendDashboard/FrontendDashboard.php 353-361
Old Code:
```php
wp_die('Login page URL not found. Please configure the settings.');
```
Fixed Code:
```php
wp_die( __( 'Login page URL not found. Please configure the settings.', 'hydra-booking' ) );
```
Explanation:
The change adds internationalization with __() but wp_die() automatically escapes HTML content by default. No user input is involved in this message, and the text is static. The output remains safe from XSS.
Vulnerability Existed: no
Cross-Site Scripting (XSS) - CWE-79 - app/FrontendDashboard/FrontendDashboard.php 380-400
Old Code:
```php
'name' => _x( 'hydra-login', 'Page slug', 'tourfic' ),
'title' => _x( 'Hydra Login', 'Page title', 'tourfic' ),
```
Fixed Code:
```php
'name' => _x( 'hydra-login', 'Page slug', 'hydra-booking' ),
'title' => _x( 'Hydra Login', 'Page title', 'hydra-booking' ),
```
Explanation:
These changes only modify the text domain from 'tourfic' to 'hydra-booking' for internationalization. The _x() function returns translated strings but doesn't automatically escape output. However, these values are used in page creation/configuration and not directly output to users without proper context. When used in WordPress page creation, the values are handled safely by WordPress core functions.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/FrontendDashboard/Shortcode/Login.php 2025-11-19 10:50:13.133808009 +0000+++ cache/hydra-booking_1.1.11/app/FrontendDashboard/Shortcode/Login.php 2025-11-19 10:50:25.784618551 +0000@@ -161,14 +161,14 @@ $required_fields = array( 'tfhb_login_user', 'tfhb_password' ); // Check nonce security if ( ! isset( $_POST['tfhb_login_nonce'] ) || ! wp_verify_nonce( $_POST['tfhb_login_nonce'], 'tfhb_check_login_nonce' ) ) {- $response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'hydra-booking' );+ $response['message'] = esc_html(__( 'Sorry, your nonce did not verify.', 'hydra-booking' )); } else { foreach ( $required_fields as $required_field ) { if ( $required_field === 'tfhb_login_user' && empty( $_POST[ $required_field ] ) ) {- $response['fieldErrors'][ $required_field] = esc_html__( 'Username or email is required.', 'tourfic' );+ $response['fieldErrors'][ $required_field] = esc_html(__( 'Username or email is required.', 'hydra-booking' )); } elseif ( $required_field === 'tfhb_password' && empty( $_POST[ $required_field ] ) ) {- $response['fieldErrors'][ $required_field] = esc_html__( 'Password is required.', 'tourfic' );+ $response['fieldErrors'][ $required_field] = esc_html(__( 'Password is required.', 'hydra-booking' )); } } }@@ -193,7 +193,7 @@ if ( is_wp_error( $user ) ) { $response['message'] = $user->get_error_message(); } else {- $response['message'] = esc_html__( 'Successfully logged in.', 'tourfic' );+ $response['message'] = esc_html(__( 'Successfully logged in.', 'hydra-booking' )); $response['success'] = true; $settings = get_option('_tfhb_frontend_dashboard_settings');
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - app/FrontendDashboard/Shortcode/Login.php 161-193
Old Code:
```php
$response['message'] = esc_html__( 'Sorry, your nonce did not verify.', 'hydra-booking' );
$response['fieldErrors'][ $required_field] = esc_html__( 'Username or email is required.', 'tourfic' );
$response['fieldErrors'][ $required_field] = esc_html__( 'Password is required.', 'tourfic' );
$response['message'] = esc_html__( 'Successfully logged in.', 'tourfic' );
```
Fixed Code:
```php
$response['message'] = esc_html(__( 'Sorry, your nonce did not verify.', 'hydra-booking' ));
$response['fieldErrors'][ $required_field] = esc_html(__( 'Username or email is required.', 'hydra-booking' ));
$response['fieldErrors'][ $required_field] = esc_html(__( 'Password is required.', 'hydra-booking' ));
$response['message'] = esc_html(__( 'Successfully logged in.', 'hydra-booking' ));
```
Explanation:
The changes involve adding explicit esc_html() function calls around translated strings that were already using esc_html__(). The original code was already safe from XSS because esc_html__() is a WordPress translation function that returns an already-escaped string. The modification adds redundant escaping by wrapping esc_html__() with esc_html(), which doesn't change the security posture. All strings being output are static translation strings, not user-controlled data. The user input from $_POST is only used for authentication checks and never directly output to the response messages.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Shortcode/HydraBookingShortcode.php 2025-11-19 10:50:13.135808137 +0000+++ cache/hydra-booking_1.1.11/app/Shortcode/HydraBookingShortcode.php 2025-11-19 10:50:25.785618615 +0000@@ -549,7 +549,7 @@ $max_book_per_slot = isset( $meta_data['max_book_per_slot'] ) ? $meta_data['max_book_per_slot'] : 1; $attendees = $check_booking->attendees; if ( count($attendees) >= $max_book_per_slot ) {- wp_send_json_error( array( 'message' => 'Already Booked' ) );+ wp_send_json_error( array( 'message' => esc_html(__('Already Booked', 'hydra-booking')) ) ); } }@@ -958,8 +958,7 @@ foreach ( $this_month_all_dates as $date ) { $all_month_data[ $date ] = $date_time->getAvailableTimeData( $meeting_id, $date, $selected_time_zone, $selected_time_format ); } - // tfhb_print_r($all_month_data);- + if ( empty( $all_month_data ) ) { wp_send_json_error( array( 'message' => esc_html(__('No time slots are currently available.', 'hydra-booking')) ) ); }
Vulnerability Existed: yes
FALSE POSITIVE
Cross-Site Scripting (XSS) - CWE-79 - app/Shortcode/HydraBookingShortcode.php 552
Old Code:
`wp_send_json_error( array( 'message' => 'Already Booked' ) );`
Fixed Code:
`wp_send_json_error( array( 'message' => esc_html(__('Already Booked', 'hydra-booking')) ) );`
Explanation:
The old code directly outputs the hardcoded string 'Already Booked' without escaping in a JSON response. While the string is hardcoded and not directly user-controlled, the wp_send_json_error function outputs JSON content that could be consumed by JavaScript. The fixed code properly escapes the translated string using esc_html(), ensuring any special characters are properly encoded if the string were to contain user input in the future or if the translation contains special characters. This is a defensive improvement to prevent potential XSS vulnerabilities.
Vulnerability Existed: no
Information Exposure - CWE-200 - app/Shortcode/HydraBookingShortcode.php 961-962
Old Code:
`// tfhb_print_r($all_month_data);`
Fixed Code:
``
Explanation:
The old code contained a commented-out debug statement (tfhb_print_r($all_month_data)) that could potentially expose sensitive information if uncommented. The fixed code removes this commented debug statement entirely. Since the code was commented and never executed, there was no actual vulnerability in the deployed code, but the removal improves code security by eliminating potential future risks if the comment were to be removed.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/app/Shortcode/ShortcodeBuilder.php 2025-11-19 10:50:13.135808137 +0000+++ cache/hydra-booking_1.1.11/app/Shortcode/ShortcodeBuilder.php 2025-11-19 10:50:25.785618615 +0000@@ -7,12 +7,13 @@ // Use Namespace use HydraBooking\DB\Meeting; use HydraBooking\DB\Host;+use HydraBooking\Admin\Controller\TransStrings; /** * Signup Class * * @author Sydur Rahman */-class ShortcodeBuilder {+class ShortcodeBuilder { /** * Constructor@@ -29,6 +30,8 @@ // Meeting categories add_shortcode('tfhb_categories', array($this, 'tfhb_categories_callback') );++ } @@ -41,28 +44,62 @@ public function tfhb_meetings_callback($atts) { $atts = shortcode_atts([- 'title' => '',- 'subtitle' => '',- 'category' => 'all', // Comma-separated category IDs- 'hosts' => 'all', // Comma-separated host IDs- 'sort_by' => 'id',- 'order_by' => 'DESC',- 'limit' => '10',+ 'title' => '',+ 'subtitle' => '',+ 'category' => 'all', // Comma-separated category IDs+ 'hosts' => 'all', // Comma-separated host IDs+ 'sort_by' => 'id',+ 'order_by' => 'DESC',+ 'limit' => '10', ], $atts, 'tfhb_meetings');+ + // Whitelisting+ $allowed_sort_by = ['id', 'title', 'created_at']; // customize as needed+ $allowed_order_by = ['ASC', 'DESC'];+ + $sort_by = in_array($atts['sort_by'], $allowed_sort_by, true) ? $atts['sort_by'] : 'id';+ $order_by = in_array(strtoupper($atts['order_by']), $allowed_order_by, true) ? strtoupper($atts['order_by']) : 'DESC';+ + // Validate sort_by+ if (!in_array($sort_by, $allowed_sort_columns, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid sorting parameter.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted sort_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_sort_columns)) . '</code></p>';+ } - // get all meetings based on given parameters- $meeting = new Meeting();- $query = array( );+ // Validate order_by+ if (!in_array($order_by, $allowed_order_directions, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid order direction.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted order_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_order_directions)) . '</code></p>';+ }+++ $limit = intval($atts['limit']);+ if ($limit <= 0) {+ $limit = 10;+ }+ + // Build secure query+ $query = [];+ // meeting_category- if('all' != $atts['category'] && !empty($atts['category'])) {- $query[] = array('meeting_category', 'IN', $atts['category']);- } + if ($atts['category'] !== 'all' && !empty($atts['category'])) {+ $category_ids = array_map('intval', explode(',', $atts['category']));+ $query[] = ['meeting_category', 'IN', $category_ids];+ }+ // meeting_host- if('all'!= $atts['hosts'] && !empty($atts['hosts'])) {- $query[] = array('host_id', 'IN', $atts['hosts']);- } - $limit = $atts['limit'] ? $atts['limit'] : 10; - $meetings = $meeting->getAll( $query, $atts['sort_by'], $atts['order_by'], $limit );+ if ($atts['hosts'] !== 'all' && !empty($atts['hosts'])) {+ $host_ids = array_map('intval', explode(',', $atts['hosts']));+ $query[] = ['host_id', 'IN', $host_ids];+ }+ + // Fetch meetings securely+ $meeting = new Meeting();+ $meetings = $meeting->getAll($query, $sort_by, $order_by, $limit); ob_start(); ?>@@ -105,7 +142,7 @@ <span> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clock"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> - <?php echo esc_html($meeting->duration) ?> minutes+ <?php echo esc_html(TransStrings::tfhbTranslateNumber($meeting->duration)) ?> <?php echo esc_html(__('minutes', 'hydra-booking')) ?> </span> <span>@@ -117,7 +154,7 @@ </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url($permalink) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html(__('Select', 'hydra-booking')) ?></a> </div> </div> @@ -154,15 +191,30 @@ 'order_by' => 'DESC', 'limit' => '10', ], $atts, 'tfhb_hosts');- // Whitelist for sort_by and order_by- $allowed_sort_columns = ['id', 'first_name', 'last_name', 'created_at']; // customize as needed+ $allowed_sort_columns = ['id', 'first_name', 'created_at']; // customize as needed $allowed_order_directions = ['ASC', 'DESC']; $sort_by = isset($atts['sort_by']) ? $atts['sort_by'] : 'id'; $order_by = isset($atts['order_by']) ? strtoupper($atts['order_by']) : 'DESC'; + // Validate sort_by+ if (!in_array($sort_by, $allowed_sort_columns, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid sorting parameter.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted sort_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_sort_columns)) . '</code></p>';+ }++ // Validate order_by+ if (!in_array($order_by, $allowed_order_directions, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid order direction.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted order_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_order_directions)) . '</code></p>';+ }+ if (!in_array($sort_by, $allowed_sort_columns, true)) { $sort_by = 'id'; }@@ -216,7 +268,7 @@ </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url( $user_url ) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url( $user_url ) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html(__('Select', 'hydra-booking')) ?></a> </div> @@ -248,23 +300,48 @@ public function tfhb_categories_callback($atts){ $atts = shortcode_atts([- 'title' => '',- 'subtitle' => '', - 'sort_by' => 'id', // id or title- 'order_by' => 'DESC',- 'limit' => '10',+ 'title' => '',+ 'subtitle' => '', + 'sort_by' => 'id', // Allowed: id or title+ 'order_by' => 'DESC',+ 'limit' => '10', ], $atts, 'tfhb_categories');+ + // Whitelist acceptable values+ $allowed_sort_by = ['id', 'name', 'slug', 'count'];+ $allowed_order_by = ['ASC', 'DESC'];+ + + $sort_by = in_array($atts['sort_by'], $allowed_sort_by, true) ? $atts['sort_by'] : 'id';+ $order_by = in_array(strtoupper($atts['order_by']), $allowed_order_by, true) ? strtoupper($atts['order_by']) : 'DESC'; - - $terms = get_terms(- array(- 'taxonomy' => 'meeting_category',- 'hide_empty' => false, // Set to true to hide empty terms- 'orderby' => $atts['sort_by'],- 'order' => $atts['order_by'],- 'number' => $atts['limit'], // Limit the number of returned terms (default: -1)- )- ); + // Validate sort_by+ if (!in_array($sort_by, $allowed_sort_columns, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid sorting parameter.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted sort_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_sort_columns)) . '</code></p>';+ }++ // Validate order_by+ if (!in_array($order_by, $allowed_order_directions, true)) {+ return '<p class="tfhb-notice notice-error"><strong>' . esc_html__('Error:', 'hydra-booking') . '</strong> ' + . esc_html__('Invalid order direction.', 'hydra-booking') . '<br>'+ . '' . esc_html__('Accepted order_by values:', 'hydra-booking') . ' <code>' + . esc_html(implode(', ', $allowed_order_directions)) . '</code></p>';+ }++ $limit = intval($atts['limit']);+ if ($limit <= 0) $limit = 10;+ + // Safe call to get_terms()+ $terms = get_terms([+ 'taxonomy' => 'meeting_category',+ 'hide_empty' => false,+ 'orderby' => $sort_by,+ 'order' => $order_by,+ 'number' => $limit,+ ]); ob_start(); ?> <div class="tfhb-category-list">@@ -289,7 +366,7 @@ </div> <div class="tfhb-meeting-list__wrap__items__actions tfhb-aling">- <a href="<?php echo esc_url($terms_archive_url) ?>" class="tfhb-btn secondary-btn">Select</a>+ <a href="<?php echo esc_url($terms_archive_url) ?>" class="tfhb-btn secondary-btn"><?php echo esc_html(__('Select', 'hydra-booking')) ?></a> </div> </div>
Vulnerability Existed: no
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') - app/Shortcode/ShortcodeBuilder.php Lines 44-106
Explanation:
The code uses a custom `Meeting::getAll()` method with array parameters for category and host IDs. User input from shortcode attributes `category` and `hosts` is processed through `array_map('intval', explode(',', $atts['category']))` and `array_map('intval', explode(',', $atts['hosts']))`, converting all values to integers. This completely neutralizes SQL injection risk as non-numeric values become 0. The query parameters are passed as arrays to what appears to be a framework query builder, preventing direct SQL string concatenation.
Vulnerability Existed: no
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') - app/Shortcode/ShortcodeBuilder.php Lines 175-280
Explanation:
The hosts shortcode uses similar protections. User input for `category` and `hosts` parameters is processed through `array_map('intval', explode(',', $atts['category']))` and `array_map('intval', explode(',', $atts['hosts']))`, converting to integers. The `Host::getAll()` method receives these sanitized array parameters, preventing SQL injection through proper parameter handling.
Vulnerability Existed: no
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') - app/Shortcode/ShortcodeBuilder.php Lines 297-370
Explanation:
The categories shortcode uses WordPress core `get_terms()` function with whitelisted parameters. User input for `sort_by` is validated against `$allowed_sort_by = ['id', 'name', 'slug', 'count']` using strict `in_array()` comparison. The `order_by` parameter is validated against `['ASC', 'DESC']` and converted to uppercase. The `limit` parameter is cast to integer with `intval()`. WordPress core functions properly handle these sanitized parameters, preventing SQL injection.
Vulnerability Existed: no
CWE-20: Improper Input Validation - app/Shortcode/ShortcodeBuilder.php Lines 44-370
Explanation:
All user input from shortcode attributes undergoes comprehensive validation. Sort parameters are whitelisted against predefined arrays using strict `in_array()` comparisons. Numeric parameters like `limit` are cast to integers with bounds checking. Category and host IDs are converted to integers via `array_map('intval')`. Invalid inputs either use safe defaults or return error messages, preventing unsafe parameter usage.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/hydra-booking.php 2025-11-19 10:50:13.204812558 +0000+++ cache/hydra-booking_1.1.11/hydra-booking.php 2025-11-19 10:50:25.839622075 +0000@@ -3,7 +3,7 @@ * Plugin Name: Hydra Booking - All in One Appointment Booking System with Automated Appointment Scheduling. * Plugin URI: https://hydrabooking.com/ * Description: Appointment Booking Plugin with Automated Scheduling - Apple/Outlook/ Google Calendar, WooCommerce, Zoom, Fluent Forms, Zapier, Mailchimp & CRM Integration.- * Version: 1.1.10+ * Version: 1.1.11 * Tested up to: 6.8 * Author: Themefic * Author URI: https://themefic.com/@@ -26,7 +26,7 @@ define( 'TFHB_PATH', plugin_dir_path( __FILE__ ) ); define( 'TFHB_URL', plugin_dir_url( __FILE__ ) ); - define( 'TFHB_VERSION', '1.1.10' );+ define( 'TFHB_VERSION', '1.1.11' ); define( 'TFHB_BASE_FILE', __FILE__);
Vulnerability Existed: no No vulnerability - No CWE - hydra-booking.php 3,26 Old Code: - * Version: 1.1.10 - define( 'TFHB_VERSION', '1.1.10' ); Fixed Code: + * Version: 1.1.11 + define( 'TFHB_VERSION', '1.1.11' ); Explanation: The changes only update the plugin version number from 1.1.10 to 1.1.11 in two locations. These are hardcoded version strings that contain no user input, no data processing, and no security-sensitive operations. There are no code changes that could introduce or fix vulnerabilities.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/includes/Includes.php 2025-11-19 10:50:13.206812686 +0000+++ cache/hydra-booking_1.1.11/includes/Includes.php 2025-11-19 10:50:25.841622204 +0000@@ -46,6 +46,7 @@ // Integrations new HydraBooking\Services\Integrations\MailChimp\MailChimp();+ new HydraBooking\Services\Integrations\Telegram\Telegram(); ?>\ No newline at end of file
Vulnerability Existed: no
No vulnerability - N/A - includes/Includes.php 46-47
Old Code:
// Integrations
new HydraBooking\Services\Integrations\MailChimp\MailChimp();
Fixed Code:
// Integrations
new HydraBooking\Services\Integrations\MailChimp\MailChimp();
new HydraBooking\Services\Integrations\Telegram\Telegram();
Explanation:
The diff shows only the addition of a new Telegram integration class instantiation. There is no user input, no data flow, no sinks, and no security-related changes. This is purely a feature addition with no security implications.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/includes/database/Booking.php 2025-11-19 10:50:13.205812622 +0000+++ cache/hydra-booking_1.1.11/includes/database/Booking.php 2025-11-19 10:50:25.839622075 +0000@@ -331,32 +331,57 @@ $data = []; if($where != null) { - foreach ($where as $condition) {- $field = $condition[0]; - if(strpos($field, '.') === false){- $field = 'booking.'.$condition[0];- } + foreach ($where as $key => $condition) {+ if ($key === 'OR' && is_array($condition)) {+ $or_sql = [];+ foreach ($condition as $or_condition) {+ $field = $or_condition[0];+ $operator = $or_condition[1];+ $value = $or_condition[2];+ + if (strpos($field, '.') === false) {+ $field = 'booking.' . $field;+ }+ + if ($operator === 'LIKE') {+ $or_sql[] = "$field $operator %s";+ $data[] = $value;+ } else {+ $or_sql[] = "$field $operator %s";+ $data[] = $value;+ }+ }+ if (!empty($or_sql)) {+ $sql .= " AND (" . implode(' OR ', $or_sql) . ")";+ }+ } else {+ $field = $condition[0]; + if(strpos($field, '.') === false){+ $field = 'booking.'.$condition[0];+ } - $operator = $condition[1];- $value = $condition[2]; - if($operator == 'BETWEEN'){ - $sql .= " AND $field $operator %s AND %s";- $data[] = $value[0];- $data[] = $value[1]; - }elseif($operator == 'IN'){ - // value is array - $in = implode(',', array_fill(0, count($value), '%s')); - $sql .= " AND $field $operator ($in)";- $data = array_merge($data, $value);- }elseif($operator == 'LIKE'){ - // if operator is like - $like_conditions[] = "$field $operator %s";- $data[] = $value; - }else{+ $operator = $condition[1];+ $value = $condition[2]; + if($operator == 'BETWEEN'){ + $sql .= " AND $field $operator %s AND %s";+ $data[] = $value[0];+ $data[] = $value[1]; + }elseif($operator == 'IN'){ + // value is array + $in = implode(',', array_fill(0, count($value), '%s')); + $sql .= " AND $field $operator ($in)";+ $data = array_merge($data, $value);+ }elseif($operator == 'LIKE'){ + // if operator is like + $like_conditions[] = "$field $operator %s";+ $data[] = $value; + }else{ - $sql .= " AND $field $operator %s";- $data[] = $value;+ $sql .= " AND $field $operator %s";+ $data[] = $value;+ } }+ } }
Vulnerability Existed: no
SQL Injection - CWE-89 - includes/database/Booking.php 331-389
Old Code:
```php
foreach ($where as $condition) {
$field = $condition[0];
if(strpos($field, '.') === false){
$field = 'booking.'.$condition[0];
}
$operator = $condition[1];
$value = $condition[2];
if($operator == 'BETWEEN'){
$sql .= " AND $field $operator %s AND %s";
$data[] = $value[0];
$data[] = $value[1];
}elseif($operator == 'IN'){
// value is array
$in = implode(',', array_fill(0, count($value), '%s'));
$sql .= " AND $field $operator ($in)";
$data = array_merge($data, $value);
}elseif($operator == 'LIKE'){
// if operator is like
$like_conditions[] = "$field $operator %s";
$data[] = $value;
}else{
$sql .= " AND $field $operator %s";
$data[] = $value;
}
}
```
Fixed Code:
```php
foreach ($where as $key => $condition) {
if ($key === 'OR' && is_array($condition)) {
$or_sql = [];
foreach ($condition as $or_condition) {
$field = $or_condition[0];
$operator = $or_condition[1];
$value = $or_condition[2];
if (strpos($field, '.') === false) {
$field = 'booking.' . $field;
}
if ($operator === 'LIKE') {
$or_sql[] = "$field $operator %s";
$data[] = $value;
} else {
$or_sql[] = "$field $operator %s";
$data[] = $value;
}
}
if (!empty($or_sql)) {
$sql .= " AND (" . implode(' OR ', $or_sql) . ")";
}
} else {
$field = $condition[0];
if(strpos($field, '.') === false){
$field = 'booking.'.$condition[0];
}
$operator = $condition[1];
$value = $condition[2];
if($operator == 'BETWEEN'){
$sql .= " AND $field $operator %s AND %s";
$data[] = $value[0];
$data[] = $value[1];
}elseif($operator == 'IN'){
// value is array
$in = implode(',', array_fill(0, count($value), '%s'));
$sql .= " AND $field $operator ($in)";
$data = array_merge($data, $value);
}elseif($operator == 'LIKE'){
// if operator is like
$like_conditions[] = "$field $operator %s";
$data[] = $value;
}else{
$sql .= " AND $field $operator %s";
$data[] = $value;
}
}
}
```
Explanation:
The code uses prepared statement placeholders (%s) for all user input values in both old and new versions. User-controlled values from $condition[2] are passed as parameters to $data array, not directly interpolated into SQL. The field names and operators are validated through conditional checks (BETWEEN, IN, LIKE) and field names are prefixed with 'booking.' if no table prefix exists. The new code adds OR condition handling but maintains the same security approach - using placeholders for values. No SQL injection vulnerability exists as user input never reaches the SQL string unsanitized.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/includes/database/Host.php 2025-11-19 10:50:13.205812622 +0000+++ cache/hydra-booking_1.1.11/includes/database/Host.php 2025-11-19 10:50:25.839622075 +0000@@ -222,7 +222,7 @@ // Sort and order- $sql .= " ORDER BY $sort_by $order_by";+ $sql .= " ORDER BY {$sort_by} {$order_by}"; // Limit if ($limit !== false) {
Vulnerability Existed: no
SQL Injection - CWE-89 - includes/database/Host.php 222
Old Code:
```php
$sql .= " ORDER BY $sort_by $order_by";
```
Fixed Code:
```php
$sql .= " ORDER BY {$sort_by} {$order_by}";
```
Explanation:
The code change only modifies string interpolation syntax from direct variable interpolation to curly brace syntax. Both versions are functionally identical in PHP and do not provide any security sanitization. The variables `$sort_by` and `$order_by` appear to be used directly in SQL ORDER BY clauses without validation or whitelisting. However, without seeing the full context of how these variables are assigned and validated earlier in the code, I cannot confirm they are attacker-controlled or reach the sink unsanitized. The diff alone shows no security improvement, but also doesn't prove vulnerability exists without the complete data flow context.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/includes/database/Meeting.php 2025-11-19 10:50:13.205812622 +0000+++ cache/hydra-booking_1.1.11/includes/database/Meeting.php 2025-11-19 10:50:25.840622139 +0000@@ -285,7 +285,7 @@ // Sort and order- $sql .= " ORDER BY tfhb_meetings.$sort_by $order_by";+ $sql .= " ORDER BY tfhb_meetings.{$sort_by} {$order_by}"; // Limit if ($limit !== false) {
Vulnerability Existed: no
SQL Injection - CWE-89 - includes/database/Meeting.php 285
Old Code:
```php
$sql .= " ORDER BY tfhb_meetings.$sort_by $order_by";
```
Fixed Code:
```php
$sql .= " ORDER BY tfhb_meetings.{$sort_by} {$order_by}";
```
Explanation:
The change is purely syntactic (curly braces for variable interpolation in a string). Both versions directly interpolate `$sort_by` and `$order_by` into the SQL query without any sanitization or parameterization. However, the code does not show where these variables come from or how they are validated. Without evidence of attacker control reaching these variables unsanitized, and without seeing the validation logic, we cannot confirm a vulnerability exists. The fix does not address SQL injection concerns.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- cache/hydra-booking_1.1.10/includes/hooks/MailHooks.php 2025-11-19 10:50:13.206812686 +0000+++ cache/hydra-booking_1.1.11/includes/hooks/MailHooks.php 2025-11-19 10:50:25.841622204 +0000@@ -826,10 +826,11 @@ $cancel_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=cancel' ); $replacements['{{booking.cancel_link}}'] = $cancel_link; }- if( $attendeeBooking->attendee_can_cancel == 1){ + if( $attendeeBooking->attendee_can_reschedule == 1){ $rescheduled_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=reschedule' ); $replacements['{{booking.rescheduled_link}}'] = $rescheduled_link; }+ // Full start end time with timezone for attendee $replacements['{{booking.full_start_end_attendee_timezone}}'] = $attendeeBooking->start_time.' - '.$attendeeBooking->end_time.' ('.$attendeeBooking->attendee_time_zone.')'; $replacements['{{booking.start_date_time_for_attendee}}'] = $attendeeBooking->start_time. ' ('.$attendeeBooking->attendee_time_zone.')';@@ -868,6 +869,49 @@ } $tags = array_keys( $replacements ); $values = array_values( $replacements ); - return str_replace( $tags, $values, $template );+ $template = str_replace( $tags, $values, $template );++ if ($attendeeBooking->attendee_can_cancel != 1 && $attendeeBooking->attendee_can_reschedule != 1) {+ libxml_use_internal_errors(true); // Suppress warnings for invalid HTML+ $dom = new \DOMDocument();+ $dom->loadHTML(mb_convert_encoding($template, 'HTML-ENTITIES', 'UTF-8'));++ $xpath = new \DOMXPath($dom);+ foreach ($xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' tfhb-cancel-reschedule-btn ')]") as $node) {+ $node->parentNode->removeChild($node);+ }++ $template = $dom->saveHTML($dom->getElementsByTagName('body')->item(0));+ $template = preg_replace('/^<body>|<\/body>$/', '', $template); // Strip body tags+ } elseif ($attendeeBooking->attendee_can_cancel == 1 && $attendeeBooking->attendee_can_reschedule != 1) {+ // Remove only cancel button+ libxml_use_internal_errors(true);+ $dom = new \DOMDocument();+ $dom->loadHTML(mb_convert_encoding($template, 'HTML-ENTITIES', 'UTF-8'));++ $xpath = new \DOMXPath($dom);+ foreach ($xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' tfhb-reschedule-btn ')]") as $node) {+ $node->parentNode->removeChild($node);+ }++ $template = $dom->saveHTML($dom->getElementsByTagName('body')->item(0));+ $template = preg_replace('/^<body>|<\/body>$/', '', $template);+ } elseif ($attendeeBooking->attendee_can_cancel != 1 && $attendeeBooking->attendee_can_reschedule == 1) {+ // Remove only cancel button+ libxml_use_internal_errors(true);+ $dom = new \DOMDocument();+ $dom->loadHTML(mb_convert_encoding($template, 'HTML-ENTITIES', 'UTF-8'));++ $xpath = new \DOMXPath($dom);+ foreach ($xpath->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' tfhb-cancel-btn ')]") as $node) {+ $node->parentNode->removeChild($node);+ }++ $template = $dom->saveHTML($dom->getElementsByTagName('body')->item(0));+ $template = preg_replace('/^<body>|<\/body>$/', '', $template);+ }++ return $template;+ } }
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - CWE-79 - includes/hooks/MailHooks.php 826-869
Old Code:
```php
if( $attendeeBooking->attendee_can_cancel == 1){
$rescheduled_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=reschedule' );
$replacements['{{booking.rescheduled_link}}'] = $rescheduled_link;
}
```
Fixed Code:
```php
if( $attendeeBooking->attendee_can_reschedule == 1){
$rescheduled_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=reschedule' );
$replacements['{{booking.rescheduled_link}}'] = $rescheduled_link;
}
```
Explanation:
The change fixes a logical error where the reschedule link was incorrectly being added based on the cancel permission (`$attendeeBooking->attendee_can_cancel`) instead of the reschedule permission (`$attendeeBooking->attendee_can_reschedule`). This is a functional bug fix, not a security vulnerability. The code uses `home_url()` for URL construction and the template replacement system uses specific placeholder tags (`{{booking.rescheduled_link}}`), which are then safely inserted into the template. The DOM manipulation that follows uses proper DOM methods to remove buttons, which is safe against XSS.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.
--- /dev/null+++ cache/hydra-booking_1.1.11/includes/services/Integrations/Telegram/Telegram.php@@ -0,0 +1,246 @@+<?php+namespace HydraBooking\Services\Integrations\Telegram;++use HydraBooking\DB\Meeting;+use HydraBooking\DB\Attendees;+use HydraBooking\DB\Host;+use HydraBooking\DB\BookingMeta;+use HydraBooking\Admin\Controller\DateTimeController;++class Telegram {++ public function __construct( ) {+ add_action( 'hydra_booking/after_booking_confirmed', array( $this, 'pushBookingToConfirmed' ), 20, 1 );+ add_action( 'hydra_booking/after_booking_canceled', array( $this, 'pushBookingToCanceled' ), 20, 1 );+ add_action( 'hydra_booking/after_booking_schedule', array( $this, 'pushBookingToscheduled' ), 20, 2 );+ }++ // Get Meeting Data+ public function getMeetingData( $meeting_id ) {+ $meeting = new Meeting();+ $meeting_data = $meeting->get( $meeting_id );+ return get_post_meta( $meeting_data->post_id, '__tfhb_meeting_opt', true );+ }++ // Get Host Data+ public function getHostData( $host_id ) {+ $host = new Host();+ $host_data = $host->getHostById( $host_id );+ return $host_data;+ }++ // If booking Status is Complted+ public function pushBookingToConfirmed( $attendees ) {++ $Meeting_meta = $this->getMeetingData( $attendees->meeting_id );+ $_tfhb_notification_settings = ! empty( $Meeting_meta['notification'] ) ? $Meeting_meta['notification'] : '';+ if ( ! empty( $_tfhb_notification_settings ) ) {+ if(!empty($_tfhb_notification_settings['telegram']['booking_confirmation']['status']) && !empty($_tfhb_notification_settings['telegram']['booking_confirmation']['body'])){+ $telegram_data = $this->tfhb_telegram_callback($_tfhb_notification_settings['telegram']['booking_confirmation']['body'], $attendees);+ }+ }+ + }++ // If booking Status is Cancel+ public function pushBookingToCanceled( $attendees ) {++ $Meeting_meta = $this->getMeetingData( $attendees->meeting_id );+ $_tfhb_notification_settings = ! empty( $Meeting_meta['notification'] ) ? $Meeting_meta['notification'] : '';++ if ( ! empty( $_tfhb_notification_settings ) ) {+ if(!empty($_tfhb_notification_settings['telegram']['booking_cancel']['status']) && !empty($_tfhb_notification_settings['telegram']['booking_cancel']['body'])){+ $telegram_data = $this->tfhb_telegram_callback($_tfhb_notification_settings['telegram']['booking_cancel']['body'], $attendees);+ }+ }++ }++ // If booking Status is ReSchedule+ public function pushBookingToscheduled( $old_booking_id, $attendees ) {+ + $Meeting_meta = $this->getMeetingData( $attendees->meeting_id );+ $_tfhb_notification_settings = ! empty( $Meeting_meta['notification'] ) ? $Meeting_meta['notification'] : '';++ if ( ! empty( $_tfhb_notification_settings ) ) {+ if(!empty($_tfhb_notification_settings['telegram']['booking_reschedule']['status']) && !empty($_tfhb_notification_settings['telegram']['booking_reschedule']['body'])){+ $telegram_data = $this->tfhb_telegram_callback($_tfhb_notification_settings['telegram']['booking_reschedule']['body'], $attendees);+ }+ }++ }++ function tfhb_telegram_callback($body, $attendees) {++ $_tfhb_host_integration_settings = is_array( get_user_meta( $attendees->host_id, '_tfhb_host_integration_settings', true ) ) ? get_user_meta( $attendees->host_id, '_tfhb_host_integration_settings', true ) : array();+ $_tfhb_integration_settings = !empty(get_option( '_tfhb_integration_settings' )) && get_option( '_tfhb_integration_settings' ) != false ? get_option( '_tfhb_integration_settings' ) : array();+ + if(!empty($_tfhb_host_integration_settings['telegram']) && !empty($_tfhb_host_integration_settings['telegram']['status']) && !empty($_tfhb_host_integration_settings['telegram']['bot_token'])){+ $telegram_status = !empty($_tfhb_host_integration_settings['telegram']['status']) ? $_tfhb_host_integration_settings['telegram']['status'] : '';+ $telegram_bot_token = !empty($_tfhb_host_integration_settings['telegram']['bot_token']) ? $_tfhb_host_integration_settings['telegram']['bot_token'] : '';+ $telegram_chat_id = !empty($_tfhb_host_integration_settings['telegram']['chat_id']) ? $_tfhb_host_integration_settings['telegram']['chat_id'] : '';+ }else{+ $telegram_status = !empty($_tfhb_integration_settings['telegram']['status']) ? $_tfhb_integration_settings['telegram']['status'] : '';+ $telegram_bot_token = !empty($_tfhb_integration_settings['telegram']['bot_token']) ? $_tfhb_integration_settings['telegram']['bot_token'] : '';+ $telegram_chat_id = !empty($_tfhb_integration_settings['telegram']['chat_id']) ? $_tfhb_integration_settings['telegram']['chat_id'] : '';+ }++ if(!empty($telegram_status) && !empty($telegram_bot_token) && !empty($telegram_chat_id)){++ $mailbody = $this->replace_mail_tags($body, $attendees->id);+ $html = preg_replace('/<\s*(br|hr)\s*\/?>/i', "\n", $mailbody);+ $html = preg_replace('/<\/?(p|div|h[1-6])[^>]*>/i', "\n", $html);+ $text = strip_tags($html);+ $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5);+ $lines = array_filter(array_map('trim', explode("\n", $text)));+ $mailbody = implode("\n", $lines);+ + $mailbody = $this->escape_markdown_v2($mailbody);++ $api_url = "https://api.telegram.org/bot$telegram_bot_token/sendMessage";+ $args = array(+ 'chat_id' => $telegram_chat_id,+ 'text' => $mailbody,+ 'parse_mode' => 'MarkdownV2'+ );++ $response = wp_remote_post( $api_url, array(+ 'body' => json_encode( $args ),+ 'headers' => array( 'Content-Type' => 'application/json' ),+ ) );++ return $response;+++ if ( is_wp_error( $response ) ) {+ error_log( 'Telegram API request failed: ' . $response->get_error_message() );+ }+ }+ }++ // Escape MarkdownV2 reserved characters+ public function escape_markdown_v2($text) {+ $special_chars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'];+ foreach ($special_chars as $char) {+ $text = str_replace($char, '\\' . $char, $text);+ }+ return $text;+ }+ /**+ * Replace all available mail tags+ */+ public function replace_mail_tags( $template, $attendee_id ) {+ + $Attendee = new Attendees();+ $attendeeBooking = $Attendee->getAttendeeWithBooking( + array(+ array('id', '=',$attendee_id),+ ),+ 1,+ 'DESC'+ ); + + // Meeting Location Check+ $meeting_locations = !is_array($attendeeBooking->meeting_locations) ? json_decode( $attendeeBooking->meeting_locations ) : $attendeeBooking->meeting_locations;+ $locations = array();+ + if ( is_array( $meeting_locations ) ) {+ foreach ( $meeting_locations as $location ) {+ if ( isset( $location->location ) ) {+ $locations[] = $location->location . (!empty($location->address) ? ' - ' . $location->address : '');+ }+ }+ }++ if ( is_object($meeting_locations) ) {+ foreach ( $meeting_locations as $key => $locationObj ) {+ if ( isset($locationObj->location) ) {+ $locations[] = $locationObj->location . (!empty($locationObj->address) ? ' - ' . $locationObj->address : '');+ }+ }+ }++ $replacements = array(+ '{{meeting.title}}' => ! empty( $attendeeBooking->meeting_title ) ? $attendeeBooking->meeting_title : '',+ '{{meeting.content}}' => ! empty( $attendeeBooking->meeting_content ) ? $attendeeBooking->meeting_content : '',+ '{{meeting.date}}' => ! empty( $attendeeBooking->meeting_dates ) ? $attendeeBooking->meeting_dates : '',+ '{{meeting.location}}' => implode( ', ', $locations ),+ '{{meeting.duration}}' => $attendeeBooking->duration,+ '{{meeting.time}}' => $attendeeBooking->start_time . '-' . $attendeeBooking->end_time,+ '{{host.name}}' => $attendeeBooking->host_first_name . ' ' . $attendeeBooking->host_last_name,+ '{{host.email}}' => ! empty( $attendeeBooking->host_email ) ? $attendeeBooking->host_email : '',+ '{{host.phone}}' => ! empty( $attendeeBooking->host_phone ) ? $attendeeBooking->host_phone : '',+ '{{attendee.name}}' => ! empty( $attendeeBooking->attendee_name ) ? $attendeeBooking->attendee_name : '',+ '{{attendee.email}}' => ! empty( $attendeeBooking->attendee_email ) ? $attendeeBooking->attendee_email : '', ++ );+ + // Additional Data+ if( !empty($attendeeBooking->others_info) && $attendeeBooking->others_info != NULL ){+ $additional_data = json_decode($attendeeBooking->others_info);+ $others_info_html = '<ul>';+ foreach ($additional_data as $key => $value) {+ $others_info_html .= '<li>'.$key.' : '.$value.'</li>'; + }+ $others_info_html .= '</ul>';+ $replacements['{{attendee.additional_data}}'] = $others_info_html;+ }+ + // reason+ if( !empty($attendeeBooking->reason) && $attendeeBooking->reason != NULL ){+ $replacements['{{booking.cancel_reason}}'] = $attendeeBooking->reason;+ $replacements['{{booking.rescheduled_reason}}'] = $attendeeBooking->reason;+ }+ + + if($attendeeBooking->attendee_can_cancel == 1){ + + $cancel_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=cancel' );+ $replacements['{{booking.cancel_link}}'] = $cancel_link;+ }+ if( $attendeeBooking->attendee_can_cancel == 1){ + $rescheduled_link = home_url( '?hydra-booking=booking&hash=' . $attendeeBooking->hash . '&meetingId=' . $attendeeBooking->meeting_id . '&type=reschedule' );+ $replacements['{{booking.rescheduled_link}}'] = $rescheduled_link;+ }+ // Full start end time with timezone for attendee + $replacements['{{booking.full_start_end_attendee_timezone}}'] = $attendeeBooking->start_time.' - '.$attendeeBooking->end_time.' ('.$attendeeBooking->attendee_time_zone.')';+ $replacements['{{booking.start_date_time_for_attendee}}'] = $attendeeBooking->start_time. ' ('.$attendeeBooking->attendee_time_zone.')';+ + + // Full start end time with timezone for host+ $dateTime = new DateTimeController( 'UTC' );+ $metting_dates = explode(',', $attendeeBooking->meeting_dates);+ if($attendeeBooking->availability_time_zone != ''){+ $full_start_end_host_timezone = $dateTime->convert_full_start_end_host_timezone_with_date( $attendeeBooking->start_time, $attendeeBooking->end_time, $attendeeBooking->attendee_time_zone, $attendeeBooking->availability_time_zone, $metting_dates[0], 'full' ); + $replacements['{{booking.full_start_end_host_timezone}}'] = $full_start_end_host_timezone;++ $start_date_time_for_host = $dateTime->convert_full_start_end_host_timezone_with_date( $attendeeBooking->start_time, $attendeeBooking->end_time, $attendeeBooking->attendee_time_zone, $attendeeBooking->availability_time_zone, $metting_dates[0], 'start' );+ $replacements['{{booking.start_date_time_for_host}}'] = $start_date_time_for_host;+ }else{+ $replacements['{{booking.full_start_end_host_timezone}}'] = $attendeeBooking->start_time.' - '.$attendeeBooking->end_time.' ('.$attendeeBooking->attendee_time_zone.')';++ $replacements['{{booking.start_date_time_for_host}}'] = $attendeeBooking->start_time. ' ('.$attendeeBooking->attendee_time_zone.')';+ }+ + if( !empty($attendeeBooking->meeting_locations) && $attendeeBooking->meeting_locations != NULL ){+ $booking_locations = json_decode($attendeeBooking->meeting_locations); + + $booking_locations_html = '';+ foreach ($booking_locations as $key => $value) { + if($key == 'zoom'){+ $link = $value->address->link;+ $password = $value->address->password; + $booking_locations_html .= '<b>'.$value->location.' :</b> <a href="'.esc_url($link).'" target="_blank">Join Meeting</a> <br> <b>Password :</b> '.esc_html($password).'<br>';+ }else{+ $booking_locations_html .= '<b>'.$value->location.' :</b> '.$value->address.'<br>'; + }+ }++ $replacements['{{booking.location_details_html}}'] = $booking_locations_html;+ } + $tags = array_keys( $replacements );+ $values = array_values( $replacements ); + return str_replace( $tags, $values, $template );+ }++}
Vulnerability Existed: no
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - CWE 79 - includes/services/Integrations/Telegram/Telegram.php [95-96]
Old Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Fixed Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Explanation:
The user input flows from template body content through replace_mail_tags() function, which performs string replacements with various data fields. The final text is processed through multiple sanitization steps: HTML tags are converted to newlines via preg_replace(), all HTML tags are removed via strip_tags(), HTML entities are decoded, and finally MarkdownV2 special characters are escaped using escape_markdown_v2(). The text is then sent to Telegram API with MarkdownV2 parse mode. Since all HTML and Markdown special characters are properly neutralized, there is no XSS vulnerability in the Telegram message context.
Vulnerability Existed: no
CWE-200: Information Exposure - CWE 200 - includes/services/Integrations/Telegram/Telegram.php [95-96]
Old Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Fixed Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Explanation:
The code processes booking information that includes meeting details, host information, and attendee data. All data flows through the same sanitization pipeline described above before being sent to Telegram. There is no evidence of unintended information exposure beyond the intended notification functionality. The data is properly formatted and escaped for the Telegram API context.
Vulnerability Existed: no
CWE-352: Cross-Site Request Forgery - CWE 352 - includes/services/Integrations/Telegram/Telegram.php [95-96]
Old Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Fixed Code:
```php
$mailbody = $this->escape_markdown_v2($mailbody);
```
Explanation:
The Telegram notification functionality is triggered by WordPress actions ('hydra_booking/after_booking_confirmed', 'hydra_booking/after_booking_canceled', 'hydra_booking/after_booking_schedule') which are internal WordPress hooks. These are not directly accessible HTTP endpoints that could be exploited via CSRF. The code only sends outbound notifications and does not process incoming requests that would require CSRF protection.
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') vulnerability in Themefic Hydra Booking hydra-booking allows SQL Injection.This issue affects Hydra Booking: from n/a through <= 1.1.10.