UserControlledHTMLAttributesScanRule meta handing lacks minimum length guard leading to false positives
Describe the bug
UserControlledHTMLAttributesScanRule (pluginId 10031, "User Controllable HTML Element Attribute (Potential XSS)") applies a false-positive guard paramValue.length() > 1 before the generic attribute check, but the <meta content> branch has no such guard: it splits the content value on [;=,] and compares every piece to every request parameter value with an exact equals.
Because virtually every responsive page carries <meta name="viewport" content="width=device-width, initial-scale=1">, the token 1 is present on every page, so any request with any parameter whose value is 1 (?page=1, ?step=1, ?submitted=1, a hidden plan_id=1 form field posted then redirected, …) raises 10031 on every such page. The alert carries no evidence, only param, so it looks like a real reflection to a downstream pipeline. Other common static meta tokens collide the same way (yes from apple-mobile-web-app-capable, noindex/nofollow from robots).
Relevant code (main): addOns/pscanrules/src/main/java/org/zaproxy/zap/extension/pscanrules/UserControlledHTMLAttributesScanRule.java — the meta branch (for (String s : attrValue.split("[;=,]")) { if (s.equals(paramValue)) { … raise } }) runs before the if (paramValue.length() > 1) block, so the single-character FP reduction that the rule already documents ("I want the value length to be greater than 1 to avoid all the false positives we're seeing when the input is limited to a single character") never applies to it.
Steps to reproduce
- Serve any HTML page with
<meta name="viewport" content="width=device-width, initial-scale=1">. - Request it as
GET /page?anything=1through ZAP with passive scanning enabled. - 10031 is raised (Informational, Low confidence, param
anything), although1is not reflected anywhere in the response.
Expected behaviour
The meta branch should apply the same paramValue.length() > 1 guard as the generic attribute branch (or skip static, well-known meta tokens), so a single-character static token from the viewport/robots/apple meta tags cannot alone trigger the alert.
Impact
In a CI/CD gate that treats new unaccepted 10031 instances as a deploy blocker, this produces a red on every page for any ?x=1-style URL — we hit it repeatedly on a redirect-after-POST query (?pm_plan_id=1, ?pm_submitted=1) with nothing reflected. We have worked around it on our side by never emitting single-character/meta-token query values, but the rule itself would benefit from the guard.
ZAP version / environment
ZAP baseline scan via the zap-baseline.py packaged image (weekly image as of 2026-09), rule source checked against zap-extensions main on 2026-09-11.
Source: zaproxy/zaproxy