Skip to content

security considerations #22

@denuoweb

Description

@denuoweb

I like the extension! My phone broke and I need better than a 4 day temporary code. Here are some security considerations. You mentioned you are releasing a new version?

Concern Explanation Mitigation
Unverified Sender in chrome.runtime.onMessage The message listener does not inspect sender.id or sender.tab.url, so any code running in a context that can call chrome.runtime.sendMessage (e.g., any permitted content script) could invoke privileged functions such as buildRequest or approveTransaction. At the top of the listener, check if (sender.id !== chrome.runtime.id) return false;. For "onLoginPage", additionally check sender.tab.url matches exactly the Duo login page domain.
Private Keys in chrome.storage.sync Private RSA keys (privateRaw) are stored in cleartext in chrome.storage.sync. This means they are synchronized (in plaintext) to Google’s servers, and if the user’s Google account is compromised, so are the keys. Switch to chrome.storage.local for all private key material. Optionally encrypt the private key under a user‑provided passphrase before storing.
Potential XSS via innerHTML on Untrusted API Data The traverse() function directly inserts Duo API transaction attributes into the DOM via p.innerHTML = … or successDetails.innerHTML = …. If Duo’s server ever returned malicious HTML or if an attacker spoofed the API, this could result in a cross‑site scripting attack. Escape all inserted strings (e.g., via a helper like escapeHtml) or use textContent and create <b> elements manually to avoid interpreting any embedded HTML.
Malicious Import Overwriting host / privateRaw / publicRaw When the user imports a base64‑encoded JSON, they (or an attacker) could inject a device whose host is not Duo’s official API. The extension might then sign requests to a malicious server (which could return arbitrary data) or leak device keys. During import, validate that every host value matches a strict Duo API domain pattern (e.g., /^api\-\d+\.duosecurity\.com$/). Perform a test GET /push/v2/device/transactions immediately after import; if it fails, reject the import.
Excessive storage.sync Quota Usage Storing large Base64‑encoded key blobs in chrome.storage.sync can exceed Chrome’s per‑item or total sync quota, resulting in failed writes or data loss. Store only minimal metadata (device IDs, click levels, names) in storage.sync. Keep the actual key blobs in storage.local, which has a much higher per‑item quota and does not synchronize to the cloud by default.
Insufficient Validation of Activation Code The code only checks the length of the two segments of the activation code. If a user accidentally enters a code with the correct length but an invalid hostname, atob(code[1]) might produce a host that is not Duo’s. The extension will then attempt to POST the public key to a possibly malicious host. Validate that host strictly matches Duo’s expected hostname pattern (e.g., ends with .duosecurity.com). Optionally perform a HEAD or simple GET /push/v2/status to confirm it is indeed Duo before proceeding.
Error Details Potentially Leaking Internal State Some catch blocks rethrow errors that embed raw exception messages (Failed to fetch <url>: <networkErr>). Those messages might be shown directly to the user in the popup. Wrap or sanitize error messages before displaying them. For internal logging, use console.error, but for UI feedback, display only user‑friendly text (e.g., “Network error, please try again later”).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions