Skip to content

Remove from what a Twig filter returns the taints its PHP callable removes - #391

Closed
danog wants to merge 6 commits into
psalm:5.xfrom
danog:twig-callable-taints
Closed

danog wants to merge 6 commits into
psalm:5.xfrom
danog:twig-callable-taints

Conversation

@danog

@danog danog commented Oct 3, 2026

Copy link
Copy Markdown
Member

Builds on #390 (and #389), whose commits come first here.

A Twig filter is PHP code, but the taint analysis passed what it is given through to what it returns whatever it does. A custom escaping filter ({{ name|esc|raw }}, with esc calling htmlspecialchars() and declaring @psalm-taint-escape html) was reported like {{ name|raw }}, and so was a filter returning a number ({{ items|length|raw }}).

What a filter returns now takes the taints of what it is given, but those its PHP callable removes: those its storage says it escapes (@psalm-taint-escape), and those its native return type cannot hold (int for length). The callable is found among the filters of the extensions given to the analysis (the last extension declaring a filter wins, as in Twig): a function, a Class::method string, a [class, method] array, or a first-class callable (self::escape(...)). A closure, or a callable Psalm does not know, removes nothing.

TemplateFileScanner (#390) is also marked @psalm-api: only configurations use it, so --find-dead-code reported it.

Tests: 2 new scenarios in TwigTaintingWithAnalyzer.feature, a filter returning a number (fails without this change) and one returning what it is given, displayed raw. The feature passes, and so does psalm --find-dead-code.

@danog
danog force-pushed the twig-callable-taints branch from 4bafd17 to 8211de8 Compare October 5, 2026 08:44
@danog
danog changed the base branch from master to 5.x October 5, 2026 08:48
@danog

danog commented Oct 5, 2026

Copy link
Copy Markdown
Member Author

Merged into #392.

@danog danog closed this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant