Skip to content

Commit 1a99afb

Browse files
committed
fix(formatter): prevent stored XSS by disabling default HTML safety
Formatters no longer treat their output as HTML safe by default. This closes a stored XSS vector where unsanitized user input could inject script content. Existing formatters must now explicitly implement isHtmlSafe() to return true *and* ensure proper escaping/sanitization before claiming safety. BREAKING CHANGE: Default formatter behavior changed; outputs are now considered unsafe HTML unless explicitly marked safe. Audit custom formatter implementations. Signed-off-by: Nicolo Singer <nicolo@whatwedo.ch>
1 parent 7e39fa7 commit 1a99afb

File tree

6 files changed

+16
-9
lines changed

6 files changed

+16
-9
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
SYMFONY_REQUIRE: ${{ matrix.symfony }}
5050
uses: ramsey/composer-install@v2
5151
- name: Run test suite on PHP ${{ matrix.php }} and Symfony ${{ matrix.symfony }}
52-
run: vendor/bin/simple-phpunit
52+
run: vendor/bin/phpunit
5353
- name: Run ECS
5454
run: vendor/bin/ecs
5555
- name: Run PHPStan

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ styles:
4141

4242
## PHP Unit
4343
phpunit:
44-
vendor/bin/simple-phpunit
44+
vendor/bin/phpunit
4545

4646

composer.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"symfony/stimulus-bundle": "^2.16"
2626
},
2727
"require-dev": {
28+
"araise/core-bundle": "dev-develop as 1.1",
29+
"araise/search-bundle": "dev-develop as 3.1",
2830
"symfony/phpunit-bridge": "^6.4|^7.0",
2931
"symfony/config": "^6.4|^7.0",
3032
"symfony/dependency-injection": "^6.4|^7.0",
@@ -40,7 +42,10 @@
4042
"symfony/webpack-encore-bundle": "^1.14|^2.1",
4143
"symfony/security-core": "^6.4|^7.0",
4244
"symfony/security-bundle": "^6.4|^7.0",
43-
"phpstan/phpstan": "^1.5"
45+
"phpstan/phpstan": "^1.5",
46+
"slevomat/coding-standard": "8.22.1",
47+
"phpunit/phpunit": "^10",
48+
"symfony/test-pack": "^1.0"
4449
},
4550
"autoload": {
4651
"psr-4": {

phpstan.neon

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,3 @@ parameters:
33
paths:
44
- src
55
- tests
6-
bootstrapFiles:
7-
- vendor/bin/.phpunit/phpunit-9.6-0/vendor/autoload.php

src/Resources/views/tailwind_2/_table.html.twig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@
221221
{% endif %}
222222
{% endif %}
223223
{% endapply %}
224-
{{ araise_table_column_render(column, row) }}
224+
{% set columnValue = araise_table_column_render(column, row) %}
225+
{{ wwd_is_html_safe(column) ? columnValue|raw : columnValue }}
225226
{% if column.option('link_the_column_content') and columnLink|default(false) %}</a>{% endif %}
226227
</td>
227228
{% endfor %}
@@ -312,7 +313,8 @@
312313
class="px-3 py-2 {{ footerColumn.option('attributes')['class'] ?? '' }}"
313314
{{ attr|map((value, attr) => "#{attr}=\"#{value}\"")|join(' ')|raw }}
314315
>
315-
{{ araise_table_column_render(footerColumn, table.footerData) }}
316+
{% set columnValue = araise_table_column_render(footerColumn, table.footerData) %}
317+
{{ wwd_is_html_safe(footerColumn) ? columnValue|raw : columnValue }}
316318
</td>
317319
{% endfor %}
318320

src/Twig/TableRenderExtension.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,20 @@ public function __construct(
2727

2828
public function getFunctions(): array
2929
{
30-
$options = [
30+
31+
$options = $noSafeOptions = [
3132
'needs_context' => true,
3233
'is_safe' => ['html'],
3334
'is_safe_callback' => true,
3435
'blockName' => 'blockName',
3536
];
37+
$noSafeOptions['is_safe'] = [];
3638

3739
return [
3840
new TwigFunction('araise_table_render', fn ($context, Table $table) => $this->renderTable($context, $table), $options),
3941
new TwigFunction('araise_table_only_render', fn ($context, Table $table) => $this->renderTable($context, $table, 'table_table'), $options),
4042
new TwigFunction('araise_table_action_render', fn ($context, Action $action, $entity) => $this->renderTableAction($context, $action, $entity), $options),
41-
new TwigFunction('araise_table_column_render', fn ($context, Column $column, $entity) => $this->renderTableColumn($context, $column, $entity), $options),
43+
new TwigFunction('araise_table_column_render', fn ($context, Column $column, $entity) => $this->renderTableColumn($context, $column, $entity), $noSafeOptions),
4244
];
4345
}
4446

0 commit comments

Comments
 (0)