Vulnerability Detail Report
Vulnerability Overview
- ZDID: ZD-2026-00909
- Vendor: Vault Manager Pro
- Title: Vault Manager Pro 密碼管理系統儲存型跨站腳本 Stored XSS
- Introduction: Vault Manager Pro 是一套純前端的企業密碼管理系統。系統在渲染密碼資料表格時,將使用者可控的欄位(帳號、密碼、資料 ID、群組名稱)以 `Utils.escape()` 進行「HTML 文字」編碼後,直接內嵌進 `onclick` 事件屬性的 JavaScript 字串中;由於瀏覽器會先將屬性值中的 HTML 實體(`'`)還原成單引號 `'` 才交給 JS 引擎解析,導致被「跳脫」過的單引號重新突破字串邊界,形成**儲存型 XSS**。攻擊者只要新增一筆惡意資料,即可在其他使用者
處理狀態
目前狀態
-
新提交
-
已審核
-
已通報
-
未回報修補狀況
-
未複測
-
公開
處理歷程
- 2026/07/08 13:44:24 : 新提交 (由 Ianon 更新此狀態)
- 2026/07/10 21:41:53 : 新提交 (由 Ianon 更新此狀態)
- 2026/07/16 10:46:52 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/07/23 16:41:12 : 審核完成 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/07/23 16:41:12 : 修補中 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/07/23 16:41:12 : 修補中 (由 HITCON ZeroDay 服務團隊 更新此狀態)
- 2026/09/07 03:00:06 : 公開 (由 HITCON ZeroDay 平台自動更新)
詳細資料
- ZDID:ZD-2026-00909
- 通報者:Ianon (Ianon)
- 風險:高
- 類型:預存式跨站腳本攻擊 (Stored Cross-Site Scripting)
參考資料
漏洞說明: OWASP - Cross-site Scripting (XSS)
https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
防護原則:
https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
XSS 防禦繞過方式:
https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
相關網址
敘述
漏洞描述
漏洞位於 /app 頁面內嵌 <script> 的 ui.renderTable() 函式。系統以字串樣板組出每一列表格,並在 onclick 屬性中內嵌使用者資料:
// 帳號 / 密碼 欄位(renderTable)
<button class="copy-btn" onclick="copyToClipboard('${Utils.escape(c.account)}')">複製</button>
<button class="copy-btn" onclick="copyToClipboard('${Utils.escape(c.password)}')">複製</button>
而 Utils.escape() 是「HTML 文字」用途的編碼器,會把 ' 轉為 ':
escape: (str) => str.replace(/[&<>"']/g,
m => ({ '&':'&', '<':'<', '>':'>', '"':'"', "'":''' }[m]));
成因:瀏覽器在解析 HTML 屬性值時,會先把 ' 還原成 ',之後才把該字串當作 JavaScript 交給引擎執行。因此當 c.account 含有單引號時,經過「跳脫」的 ' 會被還原成真正的 ',突破 onclick 內 JS 字串的邊界。這裡不需要突破標籤或屬性("、<、> 仍被編碼),僅憑一個單引號即可注入並執行任意 JavaScript。
由於 saveClient() 未做任何角色權限檢查,任何已登入的低權限「一般使用者」即可新增含惡意 payload 的資料,屬於儲存型漏洞;且該網站回應未設定 Content-Security-Policy,沒有任何緩解機制。
其他同源受影響位置(相同成因):
copyToClipboard('${Utils.escape(c.password)}')— 密碼欄位toggleSelect / editClient / deleteClient / showHistory('${Utils.escape(c.cid)}')— 資料 IDrenameTag('${Utils.escape(t)}', …)— 權限群組名稱
重現步驟
1. 進入系統並建立帳號
- 開啟
https://vaultmanagerpro.pages.dev/app - 首次使用選擇「
修補建議
1. **停止以字串樣板組出事件處理器**:
改以 `document.createElement` + `textContent` 建立表格列,並透過 `addEventListener` 綁定事件,資料以 `dataset` 或閉包 (closure) 傳遞,避免任何使用者資料進入 `onclick` 字串。
```js
const btn = document.createElement('button');
btn.textContent = '複製';
btn.dataset.value = c.account; // 不進入 HTML 字串
btn.addEventListener('click', () => copyToClipboard(btn.dataset.value));
```
2. **若仍保留內嵌處理器,需針對「JavaScript 字串」情境編碼**(而非 HTML 文字):
以 `JSON.stringify(value)` 產生安全字串常值,或對 `'` `"` `\` `<` `/` 及換行符做 `\xHH` / `\uHHHH` 跳脫,並與 HTML 屬性編碼**併用**。