fix: anchored input patterns end at the last character (/D)
Without /D, "$" also matches before a trailing "\n", so "custom_meta_telefon\n", a color setting "5\n" (stored as sent) or a whole reference followed by "\n" passed VariableRef. Added /D to every ^...$ pattern that validates client or admin input: - VariableRef META_KEY, NUMBER, WHOLE (canonical/typeOf; Placeholders::field shares META_KEY) - Cursor::decode, GuideRepository topic names (MCP input and filter keys) - ExposurePolicy::sanitize ability keys and group ids, LogTab list filters Not changed: Placeholders::PATTERN (runs on trim()), Warnings hex checks (hints only), NodeSummary/AttrPathIndex/LogListTable (stored or Divi data, no client input). Each fixed pattern has a test with a trailing "\n" that is rejected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -27,7 +27,7 @@ final class Cursor
|
||||
}
|
||||
|
||||
$raw = base64_decode(strtr($cursor, '-_', '+/'), true);
|
||||
if ($raw === false || preg_match('/^o:(\d{1,9})$/', $raw, $matches) !== 1) {
|
||||
if ($raw === false || preg_match('/^o:(\d{1,9})$/D', $raw, $matches) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ final class ExposurePolicy
|
||||
}
|
||||
} elseif (
|
||||
is_string($value)
|
||||
&& preg_match('#^[a-z0-9-]+/[a-z0-9-]+$#', $key) === 1
|
||||
&& preg_match('#^[a-z0-9-]+/[a-z0-9-]+$#D', $key) === 1
|
||||
&& self::isAllowed($key, $value)
|
||||
) {
|
||||
$clean[$key] = $value;
|
||||
@@ -275,7 +275,7 @@ final class ExposurePolicy
|
||||
/** @param list<string>|null $groupIds */
|
||||
private static function isGroupId(string $id, ?array $groupIds): bool
|
||||
{
|
||||
if (preg_match('#^[a-z0-9-]+$#', $id) !== 1) {
|
||||
if (preg_match('#^[a-z0-9-]+$#D', $id) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ final class LogTab implements AdminTab
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
return [
|
||||
'ability' => preg_match('#^[a-z0-9-]+/[a-z0-9-]+$#', $ability) === 1 ? $ability : '',
|
||||
'ability' => preg_match('#^[a-z0-9-]+/[a-z0-9-]+$#D', $ability) === 1 ? $ability : '',
|
||||
'user_id' => $userId,
|
||||
];
|
||||
}
|
||||
@@ -83,7 +83,7 @@ final class LogTab implements AdminTab
|
||||
|
||||
private static function isDate(string $value): bool
|
||||
{
|
||||
return preg_match('#^\d{4}-\d{2}-\d{2}$#', $value) === 1;
|
||||
return preg_match('#^\d{4}-\d{2}-\d{2}$#D', $value) === 1;
|
||||
}
|
||||
|
||||
public function render(): void
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace LIT\MCP\Guides;
|
||||
*/
|
||||
final class GuideRepository
|
||||
{
|
||||
private const TOPIC_PATTERN = '/^[a-z0-9]+(?:-[a-z0-9]+)*$/';
|
||||
private const TOPIC_PATTERN = '/^[a-z0-9]+(?:-[a-z0-9]+)*$/D';
|
||||
|
||||
/** @var array<string, string>|null Filtered topics, read once per instance (= request). */
|
||||
private ?array $filtered = null;
|
||||
|
||||
@@ -47,7 +47,7 @@ final class VariableRef
|
||||
public const MARKER = '$variable(';
|
||||
|
||||
/** custom_meta_<key>: no leading "_" – Divi renders protected meta publicly (ruling S12). */
|
||||
public const META_KEY = '/^[A-Za-z0-9-][A-Za-z0-9_-]*$/';
|
||||
public const META_KEY = '/^[A-Za-z0-9-][A-Za-z0-9_-]*$/D';
|
||||
|
||||
/** @var array<string, array<string, string>> Placeholders::POST values and their settings. */
|
||||
public const DEFAULT_DYNAMIC_CONTENT = [
|
||||
@@ -79,7 +79,7 @@ final class VariableRef
|
||||
|
||||
private const COLOR_SETTINGS = ['hue', 'saturation', 'lightness', 'opacity'];
|
||||
|
||||
private const WHOLE = '/^\$variable\((.*)\)\$$/s';
|
||||
private const WHOLE = '/^\$variable\((.*)\)\$$/sD';
|
||||
|
||||
private const META_PREFIX = 'custom_meta_';
|
||||
|
||||
@@ -95,7 +95,7 @@ final class VariableRef
|
||||
'loop_term_meta_key_',
|
||||
];
|
||||
|
||||
private const NUMBER = '/^-?\d+(\.\d+)?$/';
|
||||
private const NUMBER = '/^-?\d+(\.\d+)?$/D';
|
||||
|
||||
/** @var array<string, array<string, string>> */
|
||||
private array $dynamicContent;
|
||||
|
||||
Reference in New Issue
Block a user