Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/mobile-icons-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const MobileIconsBar: React.FC<MobileIconsBarProps> = ({ onAttachmentClic
<Button variant="ghost" size="icon" data-testid="mobile-search-button">
<Search className="h-[1.2rem] w-[1.2rem] transition-all rotate-0 scale-100" />
</Button>
<a href="https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00" target="_blank" rel="noopener noreferrer">
<a href="https://buy.stripe.com/14A3cv7K72TR3go14Nasg02" target="_blank" rel="noopener noreferrer">
<Button variant="ghost" size="icon">
<TentTree className="h-[1.2rem] w-[1.2rem] transition-all rotate-0 scale-100" />
</Button>
Expand Down
2 changes: 1 addition & 1 deletion components/purchase-credits-popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface PurchaseCreditsPopupProps {

export function PurchaseCreditsPopup({ isOpen, onClose }: PurchaseCreditsPopupProps) {
const handlePurchase = () => {
window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank');
window.open('https://buy.stripe.com/14A3cv7K72TR3go14Nasg02', '_blank');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

reverse tabnabbing prevention window.open _blank noopener noreferrer modern browsers best practice

💡 Result:

Reverse tabnabbing happens when a newly opened page can control the opener via window.opener (e.g., redirect it to a phishing page). The fix is to ensure the new page does not get an opener reference. [5]

Best practice (modern browsers)

1) For links (<a target="_blank">)

Use rel="noopener" (or rel="noreferrer" if you also want to suppress the Referer header):

<a href="https://example.com" target="_blank" rel="noopener">External</a>
<!-- or -->
<a href="https://example.com" target="_blank" rel="noreferrer">External</a>
  • rel="noopener" prevents window.opener from being set. [1]
  • rel="noreferrer" also implies noopener and additionally removes the Referer header. [2]
  • In modern evergreen browsers, target="_blank" implicitly behaves like rel="noopener", but it’s still common to set it explicitly for clarity/defense-in-depth (and for any non-evergreen/embedded browsers you might still care about). [1], [5]

2) For window.open()

Pass noopener (or noreferrer) in the features string:

window.open("https://example.com", "_blank", "noopener");
// or (also omits Referer)
window.open("https://example.com", "_blank", "noreferrer");

MDN documents both noopener and noreferrer as supported windowFeatures, and notes that noreferrer also enables noopener. [2]

3) Platform-level hardening (optional, stronger isolation)

Set Cross-Origin-Opener-Policy to separate browsing context groups and sever opener references more broadly:

  • Cross-Origin-Opener-Policy: same-origin (commonly used) prevents setting opener in relevant cases. [3], [4]

4) Only use an opener when you truly need it

Modern browsers generally don’t give _blank an opener unless explicitly requested (e.g., rel="opener"), so only opt into that when required. [3]


🏁 Script executed:

# Locate and verify the file and code
fd "purchase-credits-popup.tsx" --type f

Repository: QueueLab/QCX

Length of output: 93


🏁 Script executed:

# Read the file to verify the code at line 22
cat -n components/purchase-credits-popup.tsx | head -30

Repository: QueueLab/QCX

Length of output: 986


Harden window.open against reverse‑tabnabbing.

The purchase flow opens a third‑party Stripe URL with _blank, exposing window.opener to potential phishing attacks. Add noopener,noreferrer to the features parameter to prevent opener access:

🔒 Proposed fix
-    window.open('https://buy.stripe.com/14A3cv7K72TR3go14Nasg02', '_blank');
+    const newWindow = window.open(
+      'https://buy.stripe.com/14A3cv7K72TR3go14Nasg02',
+      '_blank',
+      'noopener,noreferrer'
+    );
+    if (newWindow) newWindow.opener = null;
🤖 Prompt for AI Agents
In `@components/purchase-credits-popup.tsx` at line 22, The window.open call in
components/purchase-credits-popup.tsx opens the Stripe URL with target '_blank'
and exposes window.opener; update the window.open invocation to include the
features string 'noopener,noreferrer' as the third argument (e.g.,
window.open(url, '_blank', 'noopener,noreferrer')) to prevent reverse-tabnabbing
and strip referrer data—locate the window.open call and add that third-argument
features string accordingly.

onClose();
};
Comment on lines 21 to 24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

window.open(url, '_blank') is used without noopener/noreferrer. While the app already uses rel="noopener noreferrer" for anchor-based navigation elsewhere, window.open should also protect against reverse tabnabbing via the noopener feature. This is a security footgun when opening external pages.

Suggestion

Pass window features to enforce noopener (and optionally noreferrer) for external opens, and consider centralizing this into a small helper.

window.open(STRIPE_PAYMENT_LINK_URL, '_blank', 'noopener,noreferrer');

Optionally:

export function openExternal(url: string) {
  window.open(url, '_blank', 'noopener,noreferrer');
}

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this change.


Expand Down
2 changes: 1 addition & 1 deletion components/usage-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function UsageView() {
<div className="p-4 border rounded-xl space-y-4">
<div className="flex justify-between items-center">
<span className="italic font-medium text-lg">Free</span>
<Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank')}>
<Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/14A3cv7K72TR3go14Nasg02', '_blank')}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

reverse tabnabbing prevention window.open _blank modern best practices 2024

💡 Result:

Reverse tabnabbing (via window.opener) — modern prevention best practices (2024+)

1) For HTML links (<a target="_blank">)

  • Prefer:
    <a href="https://example.com" target="_blank" rel="noopener">...</a>
  • If you also want to suppress the Referer header (privacy), use:
    <a href="https://example.com" target="_blank" rel="noreferrer">...</a>
    (noreferrer also implies noopener). [1]

Note: Modern evergreen browsers treat target="_blank" as implicitly noopener, so the issue is largely legacy—but adding rel="noopener" (or noreferrer) is still common for defense-in-depth / older clients. [2]


2) For JavaScript popups (window.open)

  • Prefer including noopener (or noreferrer) in the windowFeatures string:

    window.open(url, "_blank", "noopener");
    // or
    window.open(url, "_blank", "noreferrer"); // also implies noopener

    This prevents the new page from getting window.opener. [3][4]

  • Extra-hardening fallback (if you keep a handle):

    const w = window.open(url, "_blank", "noopener");
    if (w) w.opener = null;

    (Conceptually consistent with how browsers omit window.opener when noopener applies.) [3][5]


3) Platform/security guidance

  • If you must open a new tab/window, many security tools/guides still recommend rel="noopener noreferrer" as a safe default. [6]
  • If appropriate for your app, Cross-Origin-Opener-Policy: same-origin can also prevent window.opener from being set across origins. [5]

Sources: MDN on rel=noopener and window.open() features [1][3], OWASP on reverse tabnabbing + modern browser behavior [2], WHATWG HTML spec for noopener/noreferrer window features [4], MDN on window.opener + COOP [5], OWASP ZAP guidance [6].

References: [1] (developer.mozilla.org) [2] (owasp.org) [3] (developer.mozilla.org) [4] (html.spec.whatwg.org) [5] (developer.mozilla.org) [6] (zaproxy.org)

Citations:


🏁 Script executed:

# Check if the file exists and verify the code snippet
find . -name "usage-view.tsx" -type f

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

# Verify the exact code at line 35
sed -n '30,40p' ./components/usage-view.tsx

Repository: QueueLab/QCX

Length of output: 528


Harden window.open against reverse-tabnabbing.
Opening a third-party URL with _blank leaves window.opener exposed. Add noopener,noreferrer to the windowFeatures parameter to prevent the new tab from accessing the parent window.

🔒 Proposed fix
-            <Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/14A3cv7K72TR3go14Nasg02', '_blank')}>
+            <Button
+              size="sm"
+              className="rounded-full px-4"
+              onClick={() => window.open(
+                'https://buy.stripe.com/14A3cv7K72TR3go14Nasg02',
+                '_blank',
+                'noopener,noreferrer'
+              )}
+            >
🤖 Prompt for AI Agents
In `@components/usage-view.tsx` at line 35, The onClick handler on the Button uses
window.open(url, '_blank') which exposes window.opener; update the handler used
in the UsageView Button to call window.open with the windowFeatures string
"noopener,noreferrer" as the third argument (e.g., window.open(url, '_blank',
'noopener,noreferrer')) and optionally set opener to null as a fallback
(window.open(...); if (newWin) newWin.opener = null) to fully prevent
reverse-tabnabbing.

Upgrade
</Button>
Comment on lines +35 to 37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same window.open(..., '_blank') pattern here should include noopener,noreferrer to prevent reverse tabnabbing and keep behavior consistent with the anchor usage elsewhere.

Suggestion

Update the call to include noopener,noreferrer, ideally via a shared helper / constant.

onClick={() => window.open(STRIPE_PAYMENT_LINK_URL, '_blank', 'noopener,noreferrer')}

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this change.

</div>
Expand Down