Skip to content

test malicious code#337

Open
tintinthong wants to merge 3 commits intomainfrom
test-malicious-code
Open

test malicious code#337
tintinthong wants to merge 3 commits intomainfrom
test-malicious-code

Conversation

@tintinthong
Copy link
Copy Markdown
Contributor

No description provided.

function writeToPage(query: string) {
const params = new URLSearchParams(window.location.search);
const value = params.get(query);
document.write('<p>' + value + '</p>'); // VULNERABILITY: URL param written directly to DOM

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.

Copilot Autofix

AI 3 days ago

In general, to fix client-side XSS from URL parameters, avoid writing untrusted data as HTML. Prefer setting textContent or innerText so the browser treats the data as plain text, or apply proper HTML encoding before insertion. When using document.write, the safest fix is usually to stop using it and instead create DOM nodes and set their text content.

For this specific code, the best fix without changing visible functionality is to: (1) stop using document.write, (2) create a <p> element, and (3) assign value to textContent so that any HTML markup is escaped. To retain behavior, append this <p> to document.body. This ensures that any user-controlled content from window.location.search is rendered as text rather than executable HTML. No external libraries or new imports are needed; we only adjust the implementation of writeToPage in security-test-samples.ts.

Specifically: in security-test-samples.ts, lines 16–20 for writeToPage, replace the document.write('<p>' + value + '</p>'); line with code that creates a p element, sets p.textContent = value ?? '', and appends it to document.body. This preserves the intended display of the parameter value inside a paragraph while eliminating the XSS risk.

Suggested changeset 1
security-test-samples.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/security-test-samples.ts b/security-test-samples.ts
--- a/security-test-samples.ts
+++ b/security-test-samples.ts
@@ -16,7 +16,9 @@
 function writeToPage(query: string) {
   const params = new URLSearchParams(window.location.search);
   const value = params.get(query);
-  document.write('<p>' + value + '</p>'); // VULNERABILITY: URL param written directly to DOM
+  const p = document.createElement('p');
+  p.textContent = value ?? '';
+  document.body.appendChild(p);
 }
 
 // 3. eval() with user-controlled input
EOF
@@ -16,7 +16,9 @@
function writeToPage(query: string) {
const params = new URLSearchParams(window.location.search);
const value = params.get(query);
document.write('<p>' + value + '</p>'); // VULNERABILITY: URL param written directly to DOM
const p = document.createElement('p');
p.textContent = value ?? '';
document.body.appendChild(p);
}

// 3. eval() with user-controlled input
Copilot is powered by AI and may make mistakes. Always verify output.
function redirectTo(dest: string) {
const params = new URLSearchParams(window.location.search);
const target = params.get(dest);
window.location.href = target!; // VULNERABILITY: unvalidated redirect

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.

Copilot Autofix

AI 3 days ago

In general, to fix this kind of issue you must not directly assign user-controlled strings to navigation or HTML sinks. For redirects, a common pattern is to restrict destinations to same-origin paths or to a small whitelist of allowed relative URLs, and ignore or normalize everything else. That removes the ability for an attacker to force navigation to arbitrary domains and closes the injection path.

Here, the simplest, least invasive hardening is to make redirectTo accept only in-site relative paths. We can do this by: (1) reading the parameter as today; (2) ensuring it is non-null; (3) ensuring it starts with / and does not contain a scheme (: before any /) or protocol-relative prefix (//); and (4) assigning it only if it passes these checks. If it fails, we can either do nothing (stay on the same page) or navigate to a safe default path such as /. This preserves the function’s purpose (“redirect somewhere based on a parameter”) while preventing redirection to attacker-chosen external sites.

Concretely, in security-test-samples.ts at lines 31–35, we will:

  • Introduce a small helper isSafeRelativePath(target: string | null): target is string inside redirectTo (or inline logic) to validate the path.
  • Change window.location.href = target!; to only execute when target passes validation.
  • Optionally fall back to a safe default (e.g., /) if the parameter is missing or invalid.

No new imports are required; we use only basic string operations.

Suggested changeset 1
security-test-samples.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/security-test-samples.ts b/security-test-samples.ts
--- a/security-test-samples.ts
+++ b/security-test-samples.ts
@@ -31,7 +31,31 @@
 function redirectTo(dest: string) {
   const params = new URLSearchParams(window.location.search);
   const target = params.get(dest);
-  window.location.href = target!; // VULNERABILITY: unvalidated redirect
+
+  // Only allow same-origin relative paths to avoid open redirect / XSS
+  const isSafeRelativePath = (value: string | null): value is string => {
+    if (!value) {
+      return false;
+    }
+    // Disallow protocol-relative URLs and absolute URLs with a scheme.
+    if (value.startsWith('//')) {
+      return false;
+    }
+    const firstSlash = value.indexOf('/');
+    const firstColon = value.indexOf(':');
+    if (firstColon !== -1 && (firstSlash === -1 || firstColon < firstSlash)) {
+      return false;
+    }
+    // Require a leading slash so we only navigate within this origin.
+    return value.startsWith('/');
+  };
+
+  if (isSafeRelativePath(target)) {
+    window.location.href = target;
+  } else {
+    // Fallback to a safe default (stay on page or navigate to home).
+    // window.location.href = '/';
+  }
 }
 
 // 5. postMessage without origin check
EOF
@@ -31,7 +31,31 @@
function redirectTo(dest: string) {
const params = new URLSearchParams(window.location.search);
const target = params.get(dest);
window.location.href = target!; // VULNERABILITY: unvalidated redirect

// Only allow same-origin relative paths to avoid open redirect / XSS
const isSafeRelativePath = (value: string | null): value is string => {
if (!value) {
return false;
}
// Disallow protocol-relative URLs and absolute URLs with a scheme.
if (value.startsWith('//')) {
return false;
}
const firstSlash = value.indexOf('/');
const firstColon = value.indexOf(':');
if (firstColon !== -1 && (firstSlash === -1 || firstColon < firstSlash)) {
return false;
}
// Require a leading slash so we only navigate within this origin.
return value.startsWith('/');
};

if (isSafeRelativePath(target)) {
window.location.href = target;
} else {
// Fallback to a safe default (stay on page or navigate to home).
// window.location.href = '/';
}
}

// 5. postMessage without origin check
Copilot is powered by AI and may make mistakes. Always verify output.
window.addEventListener('message', (event) => {
// VULNERABILITY: no check on event.origin
const payload = JSON.parse(event.data);
document.getElementById('output')!.innerHTML = payload.html;

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.
function redirectTo(dest: string) {
const params = new URLSearchParams(window.location.search);
const target = params.get(dest);
window.location.href = target!; // VULNERABILITY: unvalidated redirect

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI 3 days ago

To fix client-side open redirects, user-controlled values must not be used directly as redirect URLs. Instead, the code should map user input to a restricted set of safe destinations (for example, specific paths within the same origin), or at minimum enforce same-origin and basic URL validation before redirecting.

In this snippet, the simplest safe change that preserves functionality is:

  • Interpret the query parameter as an identifier (a key), not a full URL.
  • Maintain a small client-side whitelist mapping from allowed keys to safe, same-origin paths.
  • Look up the key from URLSearchParams in this map; if it is not present, either do nothing or redirect to a neutral default (such as '/').
  • Never redirect to arbitrary absolute URLs or to user-provided strings that are not in the map.

Concretely, in security-test-samples.ts, lines 31–35 define redirectTo. We will:

  • Add a constant ALLOWED_REDIRECTS map just above redirectTo.
  • Change redirectTo so it:
    • Reads the parameter value as a key (key).
    • Finds the mapped path in ALLOWED_REDIRECTS.
    • If found, assigns that path to window.location.href.
    • If not found or missing, optionally redirects to '/' or returns without redirect; to avoid surprising behavior and still “redirect somewhere,” we’ll use '/' as a safe default.

No new imports or external libraries are needed; the change is purely within this file and function.


Suggested changeset 1
security-test-samples.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/security-test-samples.ts b/security-test-samples.ts
--- a/security-test-samples.ts
+++ b/security-test-samples.ts
@@ -28,10 +28,17 @@
 
 // 4. Open redirect via user-controlled URL
 // CodeQL rule: js/open-redirect
+const ALLOWED_REDIRECTS: Record<string, string> = {
+  home: '/',
+  dashboard: '/dashboard',
+  settings: '/settings'
+};
+
 function redirectTo(dest: string) {
   const params = new URLSearchParams(window.location.search);
-  const target = params.get(dest);
-  window.location.href = target!; // VULNERABILITY: unvalidated redirect
+  const key = params.get(dest);
+  const safeTarget = (key && ALLOWED_REDIRECTS[key]) ? ALLOWED_REDIRECTS[key] : '/';
+  window.location.href = safeTarget;
 }
 
 // 5. postMessage without origin check
EOF
@@ -28,10 +28,17 @@

// 4. Open redirect via user-controlled URL
// CodeQL rule: js/open-redirect
const ALLOWED_REDIRECTS: Record<string, string> = {
home: '/',
dashboard: '/dashboard',
settings: '/settings'
};

function redirectTo(dest: string) {
const params = new URLSearchParams(window.location.search);
const target = params.get(dest);
window.location.href = target!; // VULNERABILITY: unvalidated redirect
const key = params.get(dest);
const safeTarget = (key && ALLOWED_REDIRECTS[key]) ? ALLOWED_REDIRECTS[key] : '/';
window.location.href = safeTarget;
}

// 5. postMessage without origin check
Copilot is powered by AI and may make mistakes. Always verify output.
// 5. postMessage without origin check
// CodeQL rule: js/postmessage-star-origin (or missing origin validation)
function listenForMessages() {
window.addEventListener('message', (event) => {

Check warning

Code scanning / CodeQL

Missing origin verification in `postMessage` handler Medium

Postmessage handler has no origin check.

Copilot Autofix

AI 1 day ago

In general, the fix is to validate event.origin (and optionally event.source) in the message handler against an allowlist of trusted origins before processing event.data. If the origin is not trusted, the handler should ignore the message (or log it) and never parse or use its payload.

For this specific code, the minimal, non‑breaking change is to introduce a list of allowed origins inside listenForMessages and wrap the existing logic (JSON parsing and DOM update) in a conditional that checks event.origin against that list. We do not change what happens for trusted messages; we only prevent untrusted origins from reaching the vulnerable DOM update. Because we must not assume external configuration, we can define a simple inline array of trusted origins (e.g., ['https://www.example.com']) as a placeholder; in a real app this would be environment/config driven. The change is confined to the listenForMessages function in security-test-samples.ts; no new imports or external libraries are needed.

Concretely:

  • Edit the arrow function passed to window.addEventListener('message', ...) (lines 40–44).
  • Inside the listener, add a const trustedOrigins = [...] and an if (!trustedOrigins.includes(event.origin)) { return; }.
  • Optionally add a try/catch around JSON.parse so malformed or malicious data doesn't throw, but that’s not required by the rule; the key fix is the origin check.
  • Keep the existing behavior (parse JSON, set innerHTML) for messages from trusted origins only.
Suggested changeset 1
security-test-samples.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/security-test-samples.ts b/security-test-samples.ts
--- a/security-test-samples.ts
+++ b/security-test-samples.ts
@@ -38,7 +38,11 @@
 // CodeQL rule: js/postmessage-star-origin  (or missing origin validation)
 function listenForMessages() {
   window.addEventListener('message', (event) => {
-    // VULNERABILITY: no check on event.origin
+    const trustedOrigins = ['https://www.example.com'];
+    if (!trustedOrigins.includes(event.origin)) {
+      // Ignore messages from untrusted origins
+      return;
+    }
     const payload = JSON.parse(event.data);
     document.getElementById('output')!.innerHTML = payload.html;
   });
EOF
@@ -38,7 +38,11 @@
// CodeQL rule: js/postmessage-star-origin (or missing origin validation)
function listenForMessages() {
window.addEventListener('message', (event) => {
// VULNERABILITY: no check on event.origin
const trustedOrigins = ['https://www.example.com'];
if (!trustedOrigins.includes(event.origin)) {
// Ignore messages from untrusted origins
return;
}
const payload = JSON.parse(event.data);
document.getElementById('output')!.innerHTML = payload.html;
});
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants