Visitar URL original
[4.x] Keep allowed attributes without a value and validate attribute names by Hackwar · Pull Request #105 · joomla-framework/filter · GitHub
Skip to content

[4.x] Keep allowed attributes without a value and validate attribute names - #105

Open
Hackwar wants to merge 1 commit into
joomla-framework:4.x-devfrom
Hackwar:4.x-boolean-attributes
Open

Hackwar wants to merge 1 commit into
joomla-framework:4.x-devfrom
Hackwar:4.x-boolean-attributes

Conversation

@Hackwar

@Hackwar Hackwar commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary of Changes

Two related problems in the attribute handling of InputFilter, fixed together because the first one depends on the second:

  1. Attributes without a value were always dropped, even when allowlisted. cleanAttributes() skipped every attribute without =, and the tag parser in cleanTags() threw away valueless words that came before a / or before another attribute. So <input checked> became <input />, <details open> became <details>, and forms and details elements lost their state.
    The parser now passes those words on as attributes (unless an unquoted = value follows, which stays dropped as before), cleanAttributes() splits off valueless names that arrive in front of another attribute (checked type="checkbox"), and an allowed attribute without a value is emitted as name="". The usual allow/block lists and the on* and blocked-attribute checks apply unchanged.
  2. The attribute-name check was dead code. !preg_match('/[a-z]*$/i', $name) is never true, because the pattern matches the empty string at the end of any input; names of digits or hyphens were only removed incidentally (e.g. because they had no value). It now uses /^[a-z][a-z0-9-]*$/i, mirroring the tag-name check, so <br 3bb /> keeps losing 3bb once valueless attributes are kept, and <b 123="x"> or <b -x="x"> lose them too. data-* attributes are unaffected.

Behaviour change in 4.x: with a blocklist configuration (ONLY_BLOCK_DEFINED_ATTRIBUTES) valueless attributes such as disabled, ismap or autofocus now survive as disabled=""; with an allowlist only when they are listed. The changed expectations in the existing data providers are exactly these cases (Attribute without =, class with no =, disabled_no_equals_*, forward_slash: <textarea autofocus /onfocus=alert(1)> now gives <textarea autofocus="" /> — the onfocus handler is still removed). Attribute names that are not ASCII letters/digits/hyphens (e.g. non-Latin names) are now removed.

Testing Instructions

New tests: testCleanKeepsAllowedAttributesWithoutValue() (single, before/after a valued attribute, several, before /, details open, not allowed, on*) and testCleanRemovesInvalidAttributeNames(). Before the change 22 tests fail (12 new, 10 updated expectations); after it vendor/bin/phpunit passes.

$filter = new \Joomla\Filter\InputFilter(['input'], ['type', 'checked']);
echo $filter->clean('<input type="checkbox" checked>', 'html'); // before: <input type="checkbox" />, after: <input type="checkbox" checked="" />

Documentation Changes Required

docs/overview.md: new paragraph on attribute names and valueless attributes in "Filtering HTML"; the bullet saying valueless attributes are always dropped is removed.

Related to #104 (both edit the bullet list in "A caution about the HTML filter" in docs/overview.md; expect a small conflict there).

🤖 Generated with Claude Code

cleanAttributes() skipped every attribute without '=', and the tag
parser dropped valueless words before a '/' or before another
attribute, so '<input checked>' became '<input />' and
'<details open>' lost its state even with the attribute allowlisted.

Pass those words on as attributes and emit allowed ones as name="".
This relies on the attribute-name check, which was dead code: the
pattern '/[a-z]*$/i' matches every string. Use '/^[a-z][a-z0-9-]*$/i',
mirroring the tag-name check, so names such as '3bb' stay removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Hackwar
Hackwar force-pushed the 4.x-boolean-attributes branch from a44be56 to a81831e Compare November 12, 2026 23:39
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