Skip to content

[Security][High] Account deletion without re-auth, server-controlled nid injection chain, and FormData token handling fragility #66

Open

Description

@numbers-official

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

Activity

  1. Copilot commented on Mar 27, 2026

    Copilot
    Contributor

    The agent encountered an error and was unable to start working on this issue: This may be caused by a repository ruleset violation. See granting bypass permissions for the agent, or please contact support if the issue persists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

priority:highHigh prioritysecuritySecurity vulnerability or concern

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions