From a348c9dc820ffe7aa80588f8f0ae6b7fc210dda0 Mon Sep 17 00:00:00 2001 From: saku0512 Date: Sun, 26 Apr 2026 12:43:58 +0900 Subject: [PATCH] Fix: Enhance OpenURL function to prevent command injection and restrict protocols --- src/platforms/rcore_android.c | 15 ++++++++++++++- src/platforms/rcore_desktop_glfw.c | 14 +++++++++++++- src/platforms/rcore_desktop_rgfw.c | 14 +++++++++++++- src/platforms/rcore_desktop_sdl.c | 21 +++++++++++++++++++-- src/platforms/rcore_desktop_win32.c | 16 ++++++++++++++-- src/platforms/rcore_memory.c | 16 +++++++++++++++- src/platforms/rcore_template.c | 16 +++++++++++++++- src/platforms/rcore_web.c | 20 ++++++++++++++++++-- src/platforms/rcore_web_emscripten.c | 20 ++++++++++++++++++-- 9 files changed, 139 insertions(+), 13 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index f501fba8a..64c8f970d 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -51,6 +51,8 @@ #include // Required for: error types #include // Required for: JNIEnv and JavaVM [Used in OpenURL() and GetCurrentMonitor()] +#include +#include // Required for: isspace() #include // Native platform windowing system interface @@ -670,9 +672,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + JNIEnv *env = NULL; JavaVM *vm = platform.app->activity->vm; (*vm)->AttachCurrentThread(vm, &env, NULL); diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 9b6881d40..e13208efc 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -105,6 +105,7 @@ #endif #include // Required for: size_t +#include // Required for: isspace() //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -1191,9 +1192,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 1a4831bf1..07f16bbd2 100755 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -169,6 +169,7 @@ extern "C" { #endif #include +#include // Required for: isspace() //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -1179,9 +1180,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 277421720..3fee92e56 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -91,6 +91,9 @@ #define SCANCODE_MAPPED_NUM 232 +#include +#include // Required for: isspace() + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -1289,8 +1292,22 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else SDL_OpenURL(url); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + else + { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + + SDL_OpenURL(url); + } } //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 3f2dcd8e3..9281f19be 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -70,6 +70,7 @@ #include #include // Required for alloca() +#include // Required for: isspace() #if !defined(GRAPHICS_API_OPENGL_SOFTWARE) #include @@ -1254,9 +1255,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); sprintf(cmd, "explorer \"%s\"", url); int result = system(cmd); @@ -2271,4 +2283,4 @@ static bool IsWglExtensionAvailable(HDC hdc, const char *extension) } return result; -} \ No newline at end of file +} diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index 1512e7bf4..0a2c26485 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -52,6 +52,9 @@ #include #endif +#include +#include // Required for: isspace() + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -384,9 +387,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); sprintf(cmd, "explorer \"%s\"", url); int result = system(cmd); diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index c48484abb..508ca67d6 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -48,6 +48,9 @@ // TODO: Include the platform specific libraries +#include +#include // Required for: isspace() + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -357,9 +360,20 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); else { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + // TODO: Load url using default browser } } diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index e7e174127..3c2e773ad 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -50,6 +50,8 @@ #include // Emscripten HTML5 library #include // Required for: timespec, nanosleep(), select() - POSIX +#include +#include // Required for: isspace() //---------------------------------------------------------------------------------- // Defines and Macros @@ -997,8 +999,22 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + else + { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + + emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); + } } //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index 186813f49..78b83002b 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -45,6 +45,8 @@ #include // Emscripten HTML5 library #include // Required for: timespec, nanosleep(), select() - POSIX +#include +#include // Required for: isspace() //---------------------------------------------------------------------------------- // Defines and Macros @@ -974,8 +976,22 @@ double GetTime(void) void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + else + { + // Restriction: Only allow http:// and https:// protocols + const char *p = url; + while (*p && isspace((unsigned char)*p)) p++; + char protocol[9] = { 0 }; + for (int i = 0; (i < 8) && p[i]; i++) protocol[i] = (char)tolower((unsigned char)p[i]); + if ((strncmp(protocol, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL protocol is not allowed; only http:// and https:// are permitted"); + return; + } + + emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); + } } //----------------------------------------------------------------------------------