From 990cac09b95f7d5b5180f22bab8268f23adcf9df Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:20:00 +0000 Subject: [PATCH] Snapshots: Fix originalUrl spoof security issue (#671) --- .../dashboard/components/DashNav/DashNav.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index ac688903802..90a9b198206 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -148,6 +148,45 @@ export const DashNav = React.memo((props) => { return playlistSrv.isPlaying; }; + const originalUrl = props.dashboard.snapshot?.originalUrl ?? ''; + const gotoSnapshotOrigin = () => { + window.location.href = textUtil.sanitizeUrl(props.dashboard.snapshot.originalUrl); + }; + + const notifyApp = useAppNotification(); + const onOpenSnapshotOriginal = () => { + try { + const sanitizedUrl = new URL(textUtil.sanitizeUrl(originalUrl), config.appUrl); + const appUrl = new URL(config.appUrl); + if (sanitizedUrl.host !== appUrl.host) { + appEvents.publish( + new ShowModalReactEvent({ + component: ConfirmModal, + props: { + title: 'Proceed to external site?', + modalClass: modalStyles, + body: ( + <> +

+ {`This link connects to an external website at`} {originalUrl} +

+

{"Are you sure you'd like to proceed?"}

+ + ), + confirmVariant: 'primary', + confirmText: 'Proceed', + onConfirm: gotoSnapshotOrigin, + }, + }) + ); + } else { + gotoSnapshotOrigin(); + } + } catch (err) { + notifyApp.error('Invalid URL', err instanceof Error ? err.message : undefined); + } + }; + const renderLeftActionsButton = () => { const { dashboard, kioskMode } = props; const { canStar, canShare, isStarred } = dashboard.meta;