Skip to content

Conversation

@dennisfrancis
Copy link
Member

  • Resolves: #
  • Target version: main

Summary

TODO

  • ...

Checklist

  • I have run make prettier-write and formatted the code.
  • All commits have Change-Id
  • I have run tests with make check
  • I have issued make run and manually verified that everything looks okay
  • Documentation (manuals or wiki) has been updated or is not required

Signed-off-by: Dennis Francis <[email protected]>
Change-Id: Idcdb4e1e65796c707fdedb715d58cd50d6e05dbf
define typed base class member functions.

Signed-off-by: Dennis Francis <[email protected]>
Change-Id: Iaf24c74cb8a41469ae403fe2f26f78ada2754b9a
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I12a40c89ed6857adda43ba330bcee514ea1716b0
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I1187af813fd1ededcba43a3346f6f41ab79f32bb
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: Ib9fea6c66d7c8de45d327681d9302859557c8a3b
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I806fbfed0d2d637ca85570ab293aa969eb9dfcd4
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I11869800abfb63ddfe402ac271f09a7988052aa0
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I4a5855a883e217da18acfe5bb8840a099c9af3a8
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: Iedad8a694b62e3b26bc601d32223af3ce21a922b
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I06398740734c015908b657bf770d63f7eaa9b9a8
forClipboard: boolean,
progressFn: (progress: number) => number,
): Promise<Blob> {
const request = new XMLHttpRequest();

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 1 day ago

General approach: Ensure that any URL derived from clipboard HTML and passed into _doAsyncDownload is strictly validated and normalized before use, with no way for an attacker-controlled value to escape the constraints. Since this project already has _isClipboardURLSafe and relies on it, the best fix is to (1) normalize the URL to an absolute “safe” form, (2) avoid reusing the possibly relative or ambiguous original string in later calls, and (3) slightly tighten and clarify the safety checks.

Best concrete fix without changing external behavior:

  1. In _isClipboardURLSafe, keep using new URL(inURL, window.location.href) but:

    • Explicitly reject blob: and data: and any non-HTTP(S)/file as already done.
    • Keep the origin equality check and the /cool/clipboard path prefix rule.
    • Return false on any parsing error (already present).
      This part is mostly fine and we won’t change behavior significantly, just keep it as the central guard.
  2. In _getMetaOrigin, instead of returning inURL (the raw, decoded string), construct and return the normalized absolute URL from parsedURL inside _isClipboardURLSafe, or re-parse once we know it’s safe. Since we must not change _isClipboardURLSafe’s signature, a minimal change is:

    • After this._isClipboardURLSafe(inURL) succeeds, create a URL again from inURL with window.location.href as base and return safeURL.href instead of the original inURL.
      This guarantees that the value used later (as meta and then src/url) is a fully qualified, canonical URL that still matches the restrictions.
  3. In _dataTransferDownloadAndPasteAsync, before calling _doAsyncDownload, add a defensive check with _isClipboardURLSafe(src). This is effectively redundant with _getMetaOrigin but (a) it clearly documents the contract at the use site, and (b) if _getMetaOrigin is ever changed, this still prevents unsafe URLs from being used. If the URL fails validation, log and fall back to the existing “fallback” paste path by directly calling dataTransferToDocumentFallback.

Because we are constrained to the provided snippets, we will:

  • Adjust _getMetaOrigin in browser/src/app/ClipboardBase.ts to return a normalized absolute URL (safeURL.href) rather than the raw decoded string.
  • Add a validation guard to _dataTransferDownloadAndPasteAsync before calling _doAsyncDownload. If invalid, log and use fallbackHtml via dataTransferToDocumentFallback.

No changes are needed in browser/src/map/Clipboard.js; it only passes the clipboard HTML to dataTransferToDocument.


Suggested changeset 1
browser/src/app/ClipboardBase.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/browser/src/app/ClipboardBase.ts b/browser/src/app/ClipboardBase.ts
--- a/browser/src/app/ClipboardBase.ts
+++ b/browser/src/app/ClipboardBase.ts
@@ -282,7 +282,18 @@
 				return '';
 			}
 
-			return inURL;
+			// Normalize to an absolute, canonical URL that still respects
+			// the same-origin and path constraints enforced by
+			// _isClipboardURLSafe, and use that for any subsequent requests.
+			try {
+				const safeURL = new URL(inURL, window.location.href);
+				return safeURL.href;
+			} catch (ex: any) {
+				window.app.console.log(
+					'Failed to normalize URL: "' + inURL + '" as clipboard origin. Rejected!',
+				);
+				return '';
+			}
 		} else {
 			window.app.console.log('Mis-understood foreign origin: "' + meta + '"');
 		}
@@ -420,6 +431,24 @@
 		// FIXME: add a timestamp in the links (?) ignore old / un-responsive servers (?)
 		let response;
 		const errorMessage = _('Failed to download clipboard, please re-copy');
+
+		// Defensive check: ensure that the source URL is still considered safe
+		// before performing any network request. If not, fall back to the local
+		// clipboard contents to avoid using an attacker-controlled URL.
+		if (!this._isClipboardURLSafe(src)) {
+			window.app.console.log(
+				'Untrusted URL: "' + src + '" when downloading clipboard. Falling back to local content.',
+			);
+			this.dataTransferToDocumentFallback(
+				// No DataTransfer available here, so we pass an empty object and rely
+				// on the HTML fallback content.
+				{} as DataTransfer,
+				fallbackHtml,
+				false,
+			);
+			return;
+		}
+
 		try {
 			response = await this._doAsyncDownload(
 				'GET',
EOF
@@ -282,7 +282,18 @@
return '';
}

return inURL;
// Normalize to an absolute, canonical URL that still respects
// the same-origin and path constraints enforced by
// _isClipboardURLSafe, and use that for any subsequent requests.
try {
const safeURL = new URL(inURL, window.location.href);
return safeURL.href;
} catch (ex: any) {
window.app.console.log(
'Failed to normalize URL: "' + inURL + '" as clipboard origin. Rejected!',
);
return '';
}
} else {
window.app.console.log('Mis-understood foreign origin: "' + meta + '"');
}
@@ -420,6 +431,24 @@
// FIXME: add a timestamp in the links (?) ignore old / un-responsive servers (?)
let response;
const errorMessage = _('Failed to download clipboard, please re-copy');

// Defensive check: ensure that the source URL is still considered safe
// before performing any network request. If not, fall back to the local
// clipboard contents to avoid using an attacker-controlled URL.
if (!this._isClipboardURLSafe(src)) {
window.app.console.log(
'Untrusted URL: "' + src + '" when downloading clipboard. Falling back to local content.',
);
this.dataTransferToDocumentFallback(
// No DataTransfer available here, so we pass an empty object and rely
// on the HTML fallback content.
{} as DataTransfer,
fallbackHtml,
false,
);
return;
}

try {
response = await this._doAsyncDownload(
'GET',
Copilot is powered by AI and may make mistakes. Always verify output.
meta.indexOf('%26Tag%3D') > 0
) {
const inURL = decodeURIComponent(meta);
if (!this._isClipboardURLSafe(inURL)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

_isClipboardURLSafe() is a function I added to deal with the copilot error, but it seems not enough.

@dennisfrancis dennisfrancis requested a review from quikee January 6, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Review

Development

Successfully merging this pull request may close these issues.

1 participant