Skip to content

Commit a1c402e

Browse files
committed
security: harden URL parsing against ReDoS and injection attacks
- Add strict prefix validation: require vscode-resource://vscode-webview/ prefix - Add URI length limits (max 2048 chars) to prevent DoS - Replace potentially vulnerable regex with bounded, anchored patterns - Use ^ and $ anchors to prevent partial matches - Limit character classes to prevent backtracking (e.g., [a-zA-Z0-9._-]{1,50}) - Add proper error handling for decode failures - Addresses CodeQL warnings for polynomial regex and incomplete URL sanitization
1 parent 7029f1d commit a1c402e

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

src/integrations/misc/imageDataUrl.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,34 @@ function webviewUriToFilePath(webviewUri: string): string {
5454
}
5555

5656
// Handle VS Code webview URIs that contain encoded paths
57-
if (webviewUri.includes("vscode-userdata") || webviewUri.includes("vscode-cdn.net")) {
58-
// Try to decode the URI and extract the file path
59-
const decoded = decodeURIComponent(webviewUri)
57+
// Use strict prefix matching to prevent arbitrary host injection
58+
if (
59+
webviewUri.startsWith("vscode-resource://vscode-webview/") &&
60+
(webviewUri.includes("vscode-userdata") || webviewUri.includes("vscode-cdn.net"))
61+
) {
62+
try {
63+
// Decode safely with length limits
64+
if (webviewUri.length > 2048) {
65+
throw new Error("URI too long")
66+
}
6067

61-
// Use safer, non-polynomial regex patterns
62-
// Look for Unix-style paths first
63-
let pathMatch = decoded.match(/\/Users\/[^?#]*\.(?:png|jpg|jpeg|gif|webp)/i)
64-
if (pathMatch) {
65-
return pathMatch[0]
66-
}
68+
const decoded = decodeURIComponent(webviewUri)
6769

68-
// Look for Windows-style paths with bounded length to prevent polynomial behavior
69-
pathMatch = decoded.match(/C:\\[^?#]{0,500}\.(?:png|jpg|jpeg|gif|webp)/i)
70-
if (pathMatch) {
71-
return pathMatch[0]
70+
// Use specific, bounded patterns to prevent ReDoS
71+
// Match exact patterns without backtracking
72+
const unixMatch = decoded.match(
73+
/^[^?#]*\/Users\/[a-zA-Z0-9._-]{1,50}\/[^?#]{1,300}\.(png|jpg|jpeg|gif|webp)$/i,
74+
)
75+
if (unixMatch) {
76+
return unixMatch[0]
77+
}
78+
79+
const windowsMatch = decoded.match(/^[^?#]*C:\\[a-zA-Z0-9._\\-]{1,300}\.(png|jpg|jpeg|gif|webp)$/i)
80+
if (windowsMatch) {
81+
return windowsMatch[0]
82+
}
83+
} catch (error) {
84+
console.error("Failed to decode webview URI:", error)
7285
}
7386
}
7487

0 commit comments

Comments
 (0)