Skip to content
Merged
Changes from 1 commit
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
Next Next commit
Fixed security vulnerability on callback
  • Loading branch information
xko2x committed Oct 1, 2024
commit 7a88cc26b5e7bd79ffefcb8ae97b58966d0f2d48
59 changes: 48 additions & 11 deletions components/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,58 @@ export default function DashboardPage({
if (callback) {
const decodedCallback = decodeURIComponent(callback);
const callbackUrl = new URL(decodedCallback);
const newSearchParams = new URLSearchParams(callbackUrl.search);
const openAppParams = new URLSearchParams(openAppQueryParams);

openAppParams.forEach((value, key) => {
newSearchParams.append(key, value);
});
// Allow only same domain, localhost, pearai://, or vscode://
const allowedProtocols = ["http:", "https:", "pearai:", "vscode:"];
const isAllowedProtocol = allowedProtocols.includes(callbackUrl.protocol);

if (isAllowedProtocol) {
const isSameDomain = callbackUrl.origin === window.location.origin;
const isLocalhost = callbackUrl.hostname === "localhost";

if (callbackUrl.protocol === "http:" || callbackUrl.protocol === "https:") {
if (!isSameDomain && !isLocalhost) {
console.warn("Blocked potentially unsafe callback URL:", decodedCallback);
return;
}
}

const newSearchParams = new URLSearchParams(callbackUrl.search);
const openAppParams = new URLSearchParams(openAppQueryParams);

openAppParams.forEach((value, key) => {
newSearchParams.append(key, value);
});

callbackUrl.search = newSearchParams.toString();
const openAppUrl = callbackUrl.toString();
callbackUrl.search = newSearchParams.toString();
const openAppUrl = callbackUrl.toString();

router.push(openAppUrl);
// Ensure the final URL is still within the allowed protocols and domains
const finalUrl = new URL(openAppUrl);
const isFinalAllowedProtocol = allowedProtocols.includes(finalUrl.protocol);

const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete("callback");
window.history.replaceState({}, "", currentUrl.toString());
if (isFinalAllowedProtocol) {
if (finalUrl.protocol === "http:" || finalUrl.protocol === "https:") {
const isFinalSameDomain = finalUrl.origin === window.location.origin;
const isFinalLocalhost = finalUrl.hostname === "localhost";

if (!isFinalSameDomain && !isFinalLocalhost) {
console.warn("Blocked potentially unsafe final URL:", openAppUrl);
return;
}
}

router.push(openAppUrl);

const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete("callback");
window.history.replaceState({}, "", currentUrl.toString());
} else {
console.warn("Blocked potentially unsafe final URL:", openAppUrl);
}
} else {
console.warn("Blocked potentially unsafe callback URL:", decodedCallback);
}
}
};

Expand Down