From eb85870909ad0f5864a45bd5056dfafada35343e Mon Sep 17 00:00:00 2001 From: magdev Date: Mon, 2 Feb 2026 17:04:38 +0100 Subject: [PATCH] fix: Multi-layer protection against Twig rendering recursion - Added render depth tracking in Plugin::render() with max depth of 5 - Strip shortcodes from content when in shortcode context - Prevents any later do_shortcode() calls from triggering recursion Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 12 +++++++++++- includes/Frontend/TemplateLoader.php | 11 ++++++++++- includes/Plugin.php | 29 +++++++++++++++++++++++++++- wp-fedistream.php | 4 ++-- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21b1bc4..3cfd01b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.5] - 2026-02-02 + +### Fixed + +- **Multi-layer recursion protection** - Added additional safeguards against infinite Twig rendering + - Added render depth tracking in `Plugin::render()` with max depth of 5 + - Strip shortcodes from content when in shortcode context (prevents any later `do_shortcode()` calls from triggering recursion) + - This addresses the Twig StagingExtension.php recursion error + ## [0.4.4] - 2026-02-02 ### Fixed @@ -234,7 +243,8 @@ Initial release of WP FediStream - a WordPress plugin for streaming music over A --- -[Unreleased]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.4...HEAD +[Unreleased]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.5...HEAD +[0.4.5]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.4...v0.4.5 [0.4.4]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.3...v0.4.4 [0.4.3]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.2...v0.4.3 [0.4.2]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.1...v0.4.2 diff --git a/includes/Frontend/TemplateLoader.php b/includes/Frontend/TemplateLoader.php index eb81955..effdade 100644 --- a/includes/Frontend/TemplateLoader.php +++ b/includes/Frontend/TemplateLoader.php @@ -270,10 +270,19 @@ class TemplateLoader { $excerpt = get_the_excerpt( $post ); } + // When skipping content filter, also strip shortcodes to prevent them from + // being processed by anything else that might call do_shortcode on the output. + if ( $skip_content_filter ) { + $content = strip_shortcodes( $post->post_content ); + $content = wp_kses_post( $content ); + } else { + $content = apply_filters( 'the_content', $post->post_content ); + } + $data = array( 'id' => $post->ID, 'title' => get_the_title( $post ), - 'content' => $skip_content_filter ? wp_kses_post( $post->post_content ) : apply_filters( 'the_content', $post->post_content ), + 'content' => $content, 'excerpt' => $excerpt, 'permalink' => get_permalink( $post ), 'thumbnail' => get_the_post_thumbnail_url( $post->ID, 'large' ), diff --git a/includes/Plugin.php b/includes/Plugin.php index 5e0a9dc..035ac31 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -55,6 +55,20 @@ final class Plugin { */ private ?\Twig\Environment $twig = null; + /** + * Current Twig render depth to prevent infinite recursion. + * + * @var int + */ + private static int $render_depth = 0; + + /** + * Maximum allowed Twig render depth. + * + * @var int + */ + private const MAX_RENDER_DEPTH = 5; + /** * Post type instances. * @@ -843,7 +857,20 @@ final class Plugin { * @return string Rendered template. */ public function render( string $template, array $context = array() ): string { - return $this->twig->render( $template . '.twig', $context ); + // Prevent infinite recursion in Twig rendering. + if ( self::$render_depth >= self::MAX_RENDER_DEPTH ) { + return ''; + } + + ++self::$render_depth; + + try { + $result = $this->twig->render( $template . '.twig', $context ); + } finally { + --self::$render_depth; + } + + return $result; } /** diff --git a/wp-fedistream.php b/wp-fedistream.php index c85cd44..f9a256f 100644 --- a/wp-fedistream.php +++ b/wp-fedistream.php @@ -3,7 +3,7 @@ * Plugin Name: WP FediStream * Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-fedistream * Description: Stream music over ActivityPub - Build your own music streaming platform for Musicians and Labels. - * Version: 0.4.4 + * Version: 0.4.5 * Requires at least: 6.4 * Requires PHP: 8.3 * Author: Marco Graetsch @@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) { * * @var string */ -define( 'WP_FEDISTREAM_VERSION', '0.4.4' ); +define( 'WP_FEDISTREAM_VERSION', '0.4.5' ); /** * Plugin file path.