Overview
Deep audit (2026-03-27) identified 3 new high-severity security findings not covered by existing issues.
Finding 1: Account Deletion Without Re-authentication
File: src/services/AuthService.ts, lines 175-178
The deleteAccount() method sends a DELETE /auth/users/me/ request using only the stored auth token, with no re-authentication or password confirmation. If an attacker gains temporary access to the stored token (e.g., via another extension, compromised machine, Chrome debugger), they can permanently delete the user's account with a single API call.
async deleteAccount(): Promise<void> {
await this.apiClient.deleteWithAuth('/auth/users/me/');
this.clearAuth();
}
Impact: Irreversible account destruction with no additional verification gate.
Fix: Require current_password in the DELETE request body (Djoser standard). Add a multi-step confirmation UI.
Finding 2: Server-Controlled nid Interpolated into URLs Without Sanitization
File: src/services/UploadService.ts, line 359; src/share/share.tsx, lines 21-36
After upload, the API response's nid value is directly interpolated into a URL used to open share.html:
const nid = result.id || result.cid || result.nid;
const shareUrl = chrome.runtime.getURL(`share.html?nid=${nid}`);
The nid is server-controlled. In share.tsx, this unsanitized nid flows into innerHTML:
const verifyUrl = `https://asset.captureapp.xyz/${nid}`;
document.getElementById('root')!.innerHTML = `
<div class="verify-link">
<a href="${verifyUrl}" target="_blank">${verifyUrl}</a>
</div>`;
A crafted nid like "><img src=x onerror=alert(1)> executes JS in the extension's origin context.
Impact: XSS in extension context via compromised API response (distinct from #10 which describes the general share page XSS; this identifies the specific server-response attack vector).
Fix:
- Validate
nid with /^[a-zA-Z0-9_-]+$/ before use
- Use
encodeURIComponent(nid) in URL construction
- Replace
innerHTML with DOM API methods (textContent, createElement, setAttribute)
Finding 3: FormData Auth Token Handling with Cross-Context instanceof Fragility
File: src/services/ApiClient.ts, lines 71-83 and 128-137
buildAuthHeaders() always sets Content-Type: application/json. For FormData uploads, request() deletes this header based on body instanceof FormData. However, instanceof can fail across different global scopes (e.g., after service worker restart), causing:
- Auth token sent with wrong Content-Type
- Token potentially exposed in server error responses
Fix: Use duck-typing (body && typeof body.append === 'function') instead of instanceof. Move Content-Type decision into a dedicated uploadWithAuth method.
Generated by Heart Beat with Omni
Overview
Deep audit (2026-03-27) identified 3 new high-severity security findings not covered by existing issues.
Finding 1: Account Deletion Without Re-authentication
File:
src/services/AuthService.ts, lines 175-178The
deleteAccount()method sends aDELETE /auth/users/me/request using only the stored auth token, with no re-authentication or password confirmation. If an attacker gains temporary access to the stored token (e.g., via another extension, compromised machine, Chrome debugger), they can permanently delete the user's account with a single API call.Impact: Irreversible account destruction with no additional verification gate.
Fix: Require
current_passwordin the DELETE request body (Djoser standard). Add a multi-step confirmation UI.Finding 2: Server-Controlled
nidInterpolated into URLs Without SanitizationFile:
src/services/UploadService.ts, line 359;src/share/share.tsx, lines 21-36After upload, the API response's
nidvalue is directly interpolated into a URL used to openshare.html:The
nidis server-controlled. Inshare.tsx, this unsanitizednidflows intoinnerHTML:A crafted
nidlike"><img src=x onerror=alert(1)>executes JS in the extension's origin context.Impact: XSS in extension context via compromised API response (distinct from #10 which describes the general share page XSS; this identifies the specific server-response attack vector).
Fix:
nidwith/^[a-zA-Z0-9_-]+$/before useencodeURIComponent(nid)in URL constructioninnerHTMLwith DOM API methods (textContent,createElement,setAttribute)Finding 3: FormData Auth Token Handling with Cross-Context
instanceofFragilityFile:
src/services/ApiClient.ts, lines 71-83 and 128-137buildAuthHeaders()always setsContent-Type: application/json. For FormData uploads,request()deletes this header based onbody instanceof FormData. However,instanceofcan fail across different global scopes (e.g., after service worker restart), causing:Fix: Use duck-typing (
body && typeof body.append === 'function') instead ofinstanceof. Move Content-Type decision into a dedicateduploadWithAuthmethod.Generated by Heart Beat with Omni