Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/website-llms-txt/admin/admin-page.php
+++ b/website-llms-txt/admin/admin-page.php
@@ -75,7 +75,7 @@
<div id="llms-post-types-sortable" class="sortable-list">
<?php
$post_types = get_post_types(array('public' => true), 'objects');
- $ordered_types = array_flip($settings['post_types']); // Create lookup array
+ $ordered_types = array_flip($settings['post_types'] ?? []); // Create lookup array
$unordered_types = array(); // For types not in the current order
// Separate ordered and unordered post types
@@ -99,7 +99,7 @@
<div class="sortable-item active" data-post-type="<?php echo esc_attr($post_type->name); ?>">
<label>
<input type="checkbox" name="llms_generator_settings[post_types][]" value="<?php echo esc_attr($post_type->name); ?>" checked>
- <input type="text" name="llms_generator_settings[post_name][<?php echo esc_html($post_type->labels->name); ?>]" value="<?php echo $settings['post_name'][esc_html($post_type->labels->name)] ?? '' ?>"/>
+ <input type="text" name="llms_generator_settings[post_name][<?php echo esc_attr($post_type->labels->name); ?>]" value="<?php echo esc_attr($settings['post_name'][$post_type->labels->name] ?? '') ?>"/>
<span class="dashicons dashicons-menu"></span>
<?php echo esc_html($post_type->labels->name); ?>
<small style="opacity: 0.7;">(<?php echo intval($indexed_count) . ' indexed of ' . intval($all_count); ?>)</small>
@@ -117,7 +117,7 @@
<div class="sortable-item" data-post-type="<?php echo esc_attr($post_type->name); ?>">
<label>
<input type="checkbox" name="llms_generator_settings[post_types][]" value="<?php echo esc_attr($post_type->name); ?>"/>
- <input type="text" name="llms_generator_settings[post_name][<?php echo esc_html($post_type->labels->name); ?>]" value="<?php echo $settings['post_name'][esc_html($post_type->labels->name)] ?? '' ?>"/>
+ <input type="text" name="llms_generator_settings[post_name][<?php echo esc_attr($post_type->labels->name); ?>]" value="<?php echo esc_attr($settings['post_name'][$post_type->labels->name] ?? '') ?>"/>
<span class="dashicons dashicons-menu"></span>
<?php echo esc_html($post_type->labels->name); ?>
<small style="opacity: 0.7;">(<?php echo intval($indexed_count) . ' indexed of ' . intval($all_count); ?>)</small>
@@ -197,10 +197,10 @@
<?php if(in_array($key, ['post_types', 'max_posts', 'max_words', 'include_meta', 'include_excerpts', 'detailed_content', 'include_taxonomies', 'gform_include'])) continue ?>
<?php if(is_array($value)): ?>
<?php foreach($value as $second_key => $second_value): ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>][]" value="<?= $second_value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>][]" value="<?= esc_attr($second_value) ?>"/>
<?php endforeach ?>
<?php else: ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>]" value="<?= $value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>]" value="<?= esc_attr($value) ?>"/>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>
@@ -256,10 +256,10 @@
<?php if(in_array($key, ['include_md_file', 'noindex_header', 'llms_allow_indexing', 'update_frequency'])) continue ?>
<?php if(is_array($value)): ?>
<?php foreach($value as $second_key => $second_value): ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>][]" value="<?= $second_value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>][]" value="<?= esc_attr($second_value) ?>"/>
<?php endforeach ?>
<?php else: ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>]" value="<?= $value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>]" value="<?= esc_attr($value) ?>"/>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>
@@ -314,28 +314,28 @@
<label>
<b><?php esc_html_e('LLMS.txt Title', 'website-llms-txt'); ?></b>
</label><br/>
- <textarea name="llms_generator_settings[llms_txt_title]" style="width: 100%;height: 40px;"><?php echo (isset($settings['llms_txt_title']) ? $settings['llms_txt_title'] : '') ?></textarea>
+ <textarea name="llms_generator_settings[llms_txt_title]" style="width: 100%;height: 40px;"><?php echo esc_textarea($settings['llms_txt_title'] ?? '') ?></textarea>
<i><?php esc_html_e('Set a custom title for your LLMs.txt file. This will appear at the top of the generated file before any listed URLs.', 'website-llms-txt'); ?></i>
</p>
<p>
<label>
<b><?php esc_html_e('LLMS.txt Description', 'website-llms-txt'); ?></b>
</label><br/>
- <textarea name="llms_generator_settings[llms_txt_description]" style="width: 100%;height: 80px;"><?php echo (isset($settings['llms_txt_description']) ? $settings['llms_txt_description'] : '') ?></textarea>
+ <textarea name="llms_generator_settings[llms_txt_description]" style="width: 100%;height: 80px;"><?php echo esc_textarea($settings['llms_txt_description'] ?? '') ?></textarea>
<i><?php esc_html_e('Optional introduction text added before the list of URLs. Use this to explain the purpose or structure of your LLMs.txt file.', 'website-llms-txt'); ?></i>
</p>
<p>
<label>
<b><?php esc_html_e('LLMS.txt After Description', 'website-llms-txt'); ?></b>
</label><br/>
- <textarea name="llms_generator_settings[llms_after_txt_description]" style="width: 100%;height: 80px;"><?php echo (isset($settings['llms_after_txt_description']) ? $settings['llms_after_txt_description'] : '') ?></textarea>
+ <textarea name="llms_generator_settings[llms_after_txt_description]" style="width: 100%;height: 80px;"><?php echo esc_textarea($settings['llms_after_txt_description'] ?? '') ?></textarea>
<i><?php esc_html_e('Optional text inserted right before the list of links or content entries. You can use it to add additional notes, context, or data usage information before the URLs begin.', 'website-llms-txt'); ?></i>
</p>
<p>
<label>
<b><?php esc_html_e('LLMS.txt End File Description', 'website-llms-txt'); ?></b>
</label><br/>
- <textarea name="llms_generator_settings[llms_end_file_description]" style="width: 100%;height: 80px;"><?php echo (isset($settings['llms_end_file_description']) ? $settings['llms_end_file_description'] : '') ?></textarea>
+ <textarea name="llms_generator_settings[llms_end_file_description]" style="width: 100%;height: 80px;"><?php echo esc_textarea($settings['llms_end_file_description'] ?? '') ?></textarea>
<i><?php esc_html_e('Final text appended at the bottom of the LLMs.txt file (e.g. footer, contact, or disclaimer information).', 'website-llms-txt'); ?></i>
</p>
<?php if(!empty($settings)): ?>
@@ -343,10 +343,10 @@
<?php if(in_array($key, ['llms_txt_title', 'llms_txt_description', 'llms_after_txt_description', 'llms_end_file_description'])) continue ?>
<?php if(is_array($value)): ?>
<?php foreach($value as $second_key => $second_value): ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>][]" value="<?= $second_value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>][]" value="<?= esc_attr($second_value) ?>"/>
<?php endforeach ?>
<?php else: ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>]" value="<?= $value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>]" value="<?= esc_attr($value) ?>"/>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>
@@ -354,11 +354,9 @@
</form>
</div>
</div>
- <?php
- $tab = filter_input(INPUT_GET,'tab');
- ?>
+ <?php $tab = sanitize_key(filter_input(INPUT_GET, 'tab')); ?>
<div class="card-column">
- <div class="card <?php echo $tab; ?>">
+ <div class="card <?php echo esc_attr(sanitize_key($tab)); ?>">
<form method="post" action="options.php" id="llms-settings-crawler-form">
<?php settings_fields('llms_generator_settings'); ?>
<h2><?php esc_html_e('AI Crawler Detection','website-llms-txt') ?></h2>
@@ -383,10 +381,10 @@
<?php if(in_array($key, ['llms_local_log_enabled'])) continue ?>
<?php if(is_array($value)): ?>
<?php foreach($value as $second_key => $second_value): ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>][]" value="<?= $second_value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>][]" value="<?= esc_attr($second_value) ?>"/>
<?php endforeach ?>
<?php else: ?>
- <input type="hidden" name="llms_generator_settings[<?= $key ?>]" value="<?= $value ?>"/>
+ <input type="hidden" name="llms_generator_settings[<?= esc_attr($key) ?>]" value="<?= esc_attr($value) ?>"/>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>
--- a/website-llms-txt/includes/class-llms-generator.php
+++ b/website-llms-txt/includes/class-llms-generator.php
@@ -412,13 +412,13 @@
if(is_a($existing_page,'WP_Post')) {
$output .= "# Learn more:" . get_permalink($existing_page) . "nn";
}
- $output .= "# " . (isset($settings['llms_txt_title']) && $settings['llms_txt_title'] ? $settings['llms_txt_title'] : get_bloginfo('name')) . "nn";
+ $output .= "# " . esc_html((isset($settings['llms_txt_title']) && $settings['llms_txt_title'] ? $settings['llms_txt_title'] : get_bloginfo('name'))) . "nn";
if ($meta_description) {
- $output .= "> " . $meta_description . "nn";
+ $output .= "> " . esc_html($meta_description) . "nn";
}
if (isset($settings['llms_after_txt_description']) && $settings['llms_after_txt_description']) {
- $output .= "> " . $settings['llms_after_txt_description'] . "nn";
+ $output .= "> " . esc_html($settings['llms_after_txt_description']) . "nn";
}
$output .= "---nn";
$this->write_file(mb_convert_encoding($output, 'UTF-8', 'UTF-8'));
@@ -465,9 +465,9 @@
$post_type_obj = get_post_type_object($post_type);
if (is_object($post_type_obj) && isset($post_type_obj->labels->name)) {
- $name = $post_type_obj->labels->name;
+ $name = esc_html($post_type_obj->labels->name);
if(isset($this->settings['post_name'][$post_type_obj->labels->name]) && $this->settings['post_name'][$post_type_obj->labels->name]) {
- $name = $this->settings['post_name'][$post_type_obj->labels->name];
+ $name = esc_html($this->settings['post_name'][$post_type_obj->labels->name]);
}
$this->write_file(mb_convert_encoding("n## {$name}nn", 'UTF-8', 'UTF-8'));
@@ -651,7 +651,7 @@
$settings = apply_filters('get_llms_generator_settings', []);
if (isset($settings['llms_end_file_description']) && $settings['llms_end_file_description']) {
- $this->write_file(mb_convert_encoding('> ' . $settings['llms_end_file_description'] . "nn", 'UTF-8', 'UTF-8'));
+ $this->write_file(mb_convert_encoding('> ' . esc_html($settings['llms_end_file_description']) . "nn", 'UTF-8', 'UTF-8'));
$this->write_file(mb_convert_encoding("n---nn", 'UTF-8', 'UTF-8'));
}
}
@@ -903,9 +903,9 @@
$description = wp_trim_words(strip_tags($fallback_content), 20, '...');
}
- $overview = sprintf("- [%s](%s)%sn", $post->post_title, $permalink, $markdown . ($this->settings['include_excerpts'] && $description ? ': ' . preg_replace('/[x{00A0}x{200B}x{200C}x{200D}x{FEFF}]/u', ' ', $description) : ''));
+ $overview = sprintf("- [%s](%s)%sn", esc_html($post->post_title), esc_url($permalink), esc_html($markdown) . ($this->settings['include_excerpts'] && $description ? ': ' . preg_replace('/[x{00A0}x{200B}x{200C}x{200D}x{FEFF}]/u', ' ', esc_html($description)) : ''));
} else {
- $overview = sprintf("- [%s](%s)%sn", $post->post_title, $permalink, $markdown . ($this->settings['include_excerpts'] ? ': ' . preg_replace('/[x{00A0}x{200B}x{200C}x{200D}x{FEFF}]/u', ' ', $description) : ''));
+ $overview = sprintf("- [%s](%s)%sn", esc_html($post->post_title), esc_url($permalink), esc_html($markdown) . ($this->settings['include_excerpts'] ? ': ' . preg_replace('/[x{00A0}x{200B}x{200C}x{200D}x{FEFF}]/u', ' ', esc_html($description)) : ''));
}
$show = 1;
@@ -987,7 +987,7 @@
}
$excerpts = $this->remove_shortcodes($post->post_excerpt);
- $custom_txt = get_post_meta($post->ID, '_llmstxt_custom_note', true);
+ $custom_txt = wp_kses_post(get_post_meta($post->ID, '_llmstxt_custom_note', true));
if($custom_txt) {
$content = $custom_txt;
} else {
--- a/website-llms-txt/website-llms-txt.php
+++ b/website-llms-txt/website-llms-txt.php
@@ -2,7 +2,7 @@
/**
* Plugin Name: Website LLMs.txt
* Description: Generates and manages an llms.txt file, a structured, AI-ready index that helps large language models like ChatGPT, Claude, and Perplexity understand your site's most important content.
- * Version: 8.2.6
+ * Version: 8.2.7
* Author: Ryan Howard
* Author URI: https://completeseo.com/author/ryan-howard/
* Text Domain: website-llms-txt
@@ -18,7 +18,7 @@
}
// Define plugin constants
-define('LLMS_VERSION', '8.2.6');
+define('LLMS_VERSION', '8.2.7');
define('LLMS_PLUGIN_FILE', __FILE__);
define('LLMS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('LLMS_PLUGIN_URL', plugin_dir_url(__FILE__));