fix: Multi-layer protection against Twig rendering recursion
All checks were successful
Create Release Package / build-release (push) Successful in 57s

- 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 <noreply@anthropic.com>
This commit is contained in:
2026-02-02 17:04:38 +01:00
parent 6988e49287
commit eb85870909
4 changed files with 51 additions and 5 deletions

View File

@@ -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' ),

View File

@@ -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 '<!-- FediStream: render depth exceeded -->';
}
++self::$render_depth;
try {
$result = $this->twig->render( $template . '.twig', $context );
} finally {
--self::$render_depth;
}
return $result;
}
/**