CVE-2023-26123: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Versions of the package raysan5/raylib before 4.5.0 are vulnerable to Cross-site Scripting (XSS) such that the SetClipboardText API does not properly escape the ' character, allowing attacker-controlled input to break out of the string and execute arbitrary JavaScript via emscripten_run_script function.**Note:** This vulnerability is present only when compiling raylib for PLATFORM_WEB. All the other Desktop/Mobile/Embedded platforms are not affected.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2023-04-14T05:15Z
Repository: https://github.com/raysan5/raylib
Language: C
Files changed: src/rcore.c
Commit date: 2023-03-12 13:48:11 +0100
Commit message: ADDED: Security check for `emscripten_run_script()` #2954

Diff: diff --git a/src/rcore.c b/src/rcore.c
index d6c8325e..eae49515 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -1992,11 +1992,13 @@ void SetClipboardText(const char *text)
 {
 #if defined(PLATFORM_DESKTOP)
     glfwSetClipboardString(CORE.Window.handle, text);
 #endif
 #if defined(PLATFORM_WEB)
-    emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
+    // Security check to (partially) avoid malicious code
+    if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character");
+    else emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
 #endif
 }
 
 // Get clipboard text content
 // NOTE: returned string is allocated and freed by GLFW
@@ -2004,10 +2006,11 @@ const char *GetClipboardText(void)
 {
 #if defined(PLATFORM_DESKTOP)
     return glfwGetClipboardString(CORE.Window.handle);
 #endif
 #if defined(PLATFORM_WEB)
+/*
     // Accessing clipboard data from browser is tricky due to security reasons
     // The method to use is navigator.clipboard.readText() but this is an asynchronous method
     // that will return at some moment after the function is called with the required data
     emscripten_run_script_string("navigator.clipboard.readText() \
         .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
@@ -2017,11 +2020,11 @@ const char *GetClipboardText(void)
     // The main issue is getting that data, one approach could be using ASYNCIFY and wait
     // for the data but it requires adding Asyncify emscripten library on compilation
 
     // Another approach could be just copy the data in a HTML text field and try to retrieve it
     // later on if available... and clean it for future accesses
-
+*/
     return NULL;
 #endif
     return NULL;
 }
 
@@ -2908,10 +2911,13 @@ void SetConfigFlags(unsigned int flags)
 
 // Takes a screenshot of current screen (saved a .png)
 void TakeScreenshot(const char *fileName)
 {
 #if defined(SUPPORT_MODULE_RTEXTURES)
+    // Security check to (partially) avoid malicious code on PLATFORM_WEB
+    if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character");  return; }
+
     Vector2 scale = GetWindowScaleDPI();
     unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
     Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
 
     char path[2048] = { 0 };
@@ -3534,16 +3540,12 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
 // A user could craft a malicious string performing another action.
 // Only call this function yourself not with user input or make sure to check the string yourself.
 // Ref: https://github.com/raysan5/raylib/issues/686
 void OpenURL(const char *url)
 {
-    // Small security check trying to avoid (partially) malicious code...
-    // sorry for the inconvenience when you hit this point...
-    if (strchr(url, '\'') != NULL)
-    {
-        TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid");
-    }
+    // Security check to (aprtially) avoid malicious code on PLATFORM_WEB
+    if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
     else
     {
 #if defined(PLATFORM_DESKTOP)
         char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
     #if defined(_WIN32)

Vulnerable code:     emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));

    // Small security check trying to avoid (partially) malicious code...
    // sorry for the inconvenience when you hit this point...
    if (strchr(url, '\'') != NULL)
    {
        TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid");
    }
Fixed code:     // Security check to (partially) avoid malicious code
    if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character");
    else emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
/*
*/
    // Security check to (partially) avoid malicious code on PLATFORM_WEB
    if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character");  return; }

    // Security check to (aprtially) avoid malicious code on PLATFORM_WEB
    if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");