Skip to content

Commit 49d4c18

Browse files
1 parent 10aa2cd commit 49d4c18

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-hvqh-jw65-wcpq",
4+
"modified": "2026-06-22T23:00:50Z",
5+
"published": "2026-06-22T23:00:50Z",
6+
"aliases": [],
7+
"summary": "devbridge-autocomplete has XSS in its default formatters: formatGroup and formatResult fail to escape HTML in untrusted inputs",
8+
"details": "### Summary\n\nThe default `formatGroup` and `formatResult` functions in `devbridge-autocomplete` concatenate values into HTML without escaping, allowing XSS when an attacker controls (or can taint) the suggestion data source.\n\n### Details\n\n**1. `formatGroup` — `category` is interpolated raw.**\n\n`src/format.ts`:\n\n```ts\nfunction formatGroup(suggestion, category) {\n return '<div class=\"autocomplete-group\">' + category + '</div>';\n}\n```\n\nIf `groupBy` is used and the grouping field of any suggestion contains HTML, that HTML is executed.\n\n**2. `formatResult` — early-return branch returns `suggestion.value` raw.**\n\n`src/format.ts`:\n\n```ts\nfunction formatResult(suggestion, currentValue) {\n if (!currentValue) {\n return suggestion.value; // un-escaped\n }\n /* ... non-empty path escapes correctly ... */\n}\n```\n\nThe early-return branch is reached when `suggest()` renders with an empty `currentValue`, which happens with `minChars: 0` and a server that returns suggestions for an empty query. The returned string is concatenated into the container's `innerHTML`.\n\n### PoC (formatGroup)\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>PoC: formatGroup XSS in jQuery-Autocomplete v2.0.0</title>\n</head>\n<body>\n <input id=\"ac\" type=\"text\" placeholder=\"Type 'a' to trigger\" autocomplete=\"off\">\n\n <script src=\"https://code.jquery.com/jquery-3.7.1.min.js\"></script>\n <script src=\"dist/jquery.autocomplete.js\"></script>\n <script>\n var poisoned = [\n { value: 'Apple', data: { category: \"<img src=x onerror=\\\"alert('XSS via formatGroup')\\\">\" } },\n { value: 'Avocado', data: { category: 'Safe Group' } }\n ];\n\n $('#ac').devbridgeAutocomplete({\n lookup: poisoned,\n groupBy: 'category',\n minChars: 1\n });\n </script>\n</body>\n</html>\n```\n\nOriginally identified by an earlier human analysis; the PoC above was produced with the assistance of Claude Opus 4.7.\n\n### Impact\n\nXSS in pages that render attacker-controllable suggestion data. The actual impact depends on what the embedding page has access to (cookies, session tokens, DOM), per standard reflected/stored XSS.\n\n### Patch\n\nBoth formatters now run their interpolated input through the browser's text-node escaping (`createElement` + `textContent`) before producing the HTML string. Fixed in version `2.0.1`.",
9+
"severity": [
10+
{
11+
"type": "CVSS_V3",
12+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "npm",
19+
"name": "devbridge-autocomplete"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "0"
27+
},
28+
{
29+
"fixed": "2.0.1"
30+
}
31+
]
32+
}
33+
],
34+
"database_specific": {
35+
"last_known_affected_version_range": "<= 2.0.0"
36+
}
37+
}
38+
],
39+
"references": [
40+
{
41+
"type": "WEB",
42+
"url": "https://github.com/devbridge/jQuery-Autocomplete/security/advisories/GHSA-hvqh-jw65-wcpq"
43+
},
44+
{
45+
"type": "WEB",
46+
"url": "https://github.com/devbridge/jQuery-Autocomplete/commit/63ff096ff5b77a90aac7fb5dad7c86e538a59ce0"
47+
},
48+
{
49+
"type": "PACKAGE",
50+
"url": "https://github.com/devbridge/jQuery-Autocomplete"
51+
}
52+
],
53+
"database_specific": {
54+
"cwe_ids": [
55+
"CWE-79"
56+
],
57+
"severity": "MODERATE",
58+
"github_reviewed": true,
59+
"github_reviewed_at": "2026-06-22T23:00:50Z",
60+
"nvd_published_at": null
61+
}
62+
}

0 commit comments

Comments
 (0)