Skip to content
This repository was archived by the owner on Oct 1, 2025. It is now read-only.
This repository was archived by the owner on Oct 1, 2025. It is now read-only.

REDCap module security scan fails #1

@pbchase

Description

@pbchase

The REDCap module security scan fails:

# bin/scan modules/multilingual_v0.0.0

...... 6 / 6 (100%)


Time: 441ms; Memory: 18MB


------------------------------------------------------------
Running Psalm's Taint Analysis

ERROR: TaintedHtml - Multilingual.php:98:9 - Detected tainted HTML (see https://psalm.dev/245)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  $_GET
    <no known location>

  $_GET['page'] - Multilingual.php:97:18
                        $instrument = $_GET['page'];

  $instrument - Multilingual.php:97:4
                        $instrument = $_GET['page'];

  call to str_replace - Multilingual.php:101:42
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,

  str_replace#2 - Multilingual.php:101:42
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  call to str_replace - Multilingual.php:101:4
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace#3 - Multilingual.php:101:4
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  call to str_replace - Multilingual.php:100:4
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace#3 - Multilingual.php:100:4
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  concat - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  concat - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  call to echo - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';



ERROR: TaintedTextWithQuotes - Multilingual.php:98:9 - Detected tainted text with possible quotes (see https://psalm.dev/274)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  $_GET
    <no known location>

  $_GET['page'] - Multilingual.php:97:18
                        $instrument = $_GET['page'];

  $instrument - Multilingual.php:97:4
                        $instrument = $_GET['page'];

  call to str_replace - Multilingual.php:101:42
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,

  str_replace#2 - Multilingual.php:101:42
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  call to str_replace - Multilingual.php:101:4
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace#3 - Multilingual.php:101:4
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  call to str_replace - Multilingual.php:100:4
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace#3 - Multilingual.php:100:4
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  str_replace - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:850:10
function str_replace($search, $replace, $subject, &$count = null) {}

  concat - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  concat - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';

  call to echo - Multilingual.php:98:9
                        echo '<script type="text/javascript">' .
                        str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES,
                        str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id),
                        str_replace('REDCAP_INSTRUMENT_NAME', $instrument,
                        str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)),
                        file_get_contents($this->getModulePath() . 'js/multilingual_survey_return.js'))))) . '</script>';



ERROR: TaintedSql - Multilingual.php:240:33 - Detected tainted SQL (see https://psalm.dev/244)
To resolve this, use the $module->query() method and pass the variable highlighted at the last step of the trace
as a parameter via the second argument to the query() method (for details, see the documentation for this method).

  $_POST
    <no known location>

  $_POST['data'] - index.php:7:11
        $data = @$_POST['data'];

  $data - index.php:7:2
        $data = @$_POST['data'];

  call to json_decode - index.php:9:23
                $data = json_decode($data, true);

  json_decode#1 - index.php:9:23
                $data = json_decode($data, true);

  json_decode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1317:10
function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) {}

  $data - index.php:9:3
                $data = json_decode($data, true);

  call to CMH\Multilingual\Multilingual::getAnswers - index.php:21:25
                                $module->getAnswers($data);

  CMH\Multilingual\Multilingual::getAnswers#1 - Multilingual.php:221:29
        public function getAnswers($data){

  $data - Multilingual.php:221:29
        public function getAnswers($data){

  $data - Multilingual.php:224:3
                $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']);

  $data - Multilingual.php:225:3
                $data['field_name'] = mysqli_real_escape_string($conn, $data['field_name']);

  $data['field_name'] - Multilingual.php:238:30
                                AND field_name LIKE '" . $data['field_name'] . "'";

  concat - Multilingual.php:236:13
                        $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName
                                WHERE project_id = " . intval($data['project_id']) . "
                                AND field_name LIKE '" . $data['field_name'] . "'";

  concat - Multilingual.php:236:13
                        $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName
                                WHERE project_id = " . intval($data['project_id']) . "
                                AND field_name LIKE '" . $data['field_name'] . "'";

  $query - Multilingual.php:236:4
                        $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName

  call to mysqli_query - Multilingual.php:240:33
                $result = mysqli_query($conn, $query);



ERROR: TaintedHtml - Multilingual.php:293:8 - Detected tainted HTML (see https://psalm.dev/245)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  mysqli_fetch_array - Multilingual.php:133:15
                                if($row = mysqli_fetch_array($result)){

  $row - Multilingual.php:242:3
                $row = mysqli_fetch_array($result);

  $row['element_enum'] - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  call to explode - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  explode#2 - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  explode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:702:72
function explode(string $separator, string $string, int $limit = -1) : array {}

  $tmp - Multilingual.php:248:4
                        $tmp = explode('\n', $row['element_enum']);

  arrayvalue-fetch - Multilingual.php:251:11
                foreach($tmp AS $key => $value){

  $value - Multilingual.php:251:27
                foreach($tmp AS $key => $value){

  call to explode - Multilingual.php:252:25
                        $tmp2 = explode(',', $value);

  explode#2 - Multilingual.php:252:25
                        $tmp2 = explode(',', $value);

  explode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:702:72
function explode(string $separator, string $string, int $limit = -1) : array {}

  $tmp2 - Multilingual.php:252:4
                        $tmp2 = explode(',', $value);

  $tmp2[1] - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  call to trim - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  trim#1 - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  trim - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:617:71
function trim(string $string, string $characters = " \t\n\r\0\x0B") : string {}

  $response - Multilingual.php:253:4
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  call to json_encode - Multilingual.php:293:20
                echo json_encode($response);

  json_encode#1 - Multilingual.php:293:20
                echo json_encode($response);

  json_encode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1327:10
function json_encode(mixed $value, int $flags = 0, int $depth = 512) {}

  call to echo - Multilingual.php:293:8
                echo json_encode($response);



ERROR: TaintedTextWithQuotes - Multilingual.php:293:8 - Detected tainted text with possible quotes (see https://psalm.dev/274)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  mysqli_fetch_array - Multilingual.php:133:15
                                if($row = mysqli_fetch_array($result)){

  $row - Multilingual.php:242:3
                $row = mysqli_fetch_array($result);

  $row['element_enum'] - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  call to explode - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  explode#2 - Multilingual.php:248:25
                        $tmp = explode('\n', $row['element_enum']);

  explode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:702:72
function explode(string $separator, string $string, int $limit = -1) : array {}

  $tmp - Multilingual.php:248:4
                        $tmp = explode('\n', $row['element_enum']);

  arrayvalue-fetch - Multilingual.php:251:11
                foreach($tmp AS $key => $value){

  $value - Multilingual.php:251:27
                foreach($tmp AS $key => $value){

  call to explode - Multilingual.php:252:25
                        $tmp2 = explode(',', $value);

  explode#2 - Multilingual.php:252:25
                        $tmp2 = explode(',', $value);

  explode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:702:72
function explode(string $separator, string $string, int $limit = -1) : array {}

  $tmp2 - Multilingual.php:252:4
                        $tmp2 = explode(',', $value);

  $tmp2[1] - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  call to trim - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  trim#1 - Multilingual.php:253:37
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  trim - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:617:71
function trim(string $string, string $characters = " \t\n\r\0\x0B") : string {}

  $response - Multilingual.php:253:4
                        $response[trim($tmp2[0])] = trim($tmp2[1]);

  call to json_encode - Multilingual.php:293:20
                echo json_encode($response);

  json_encode#1 - Multilingual.php:293:20
                echo json_encode($response);

  json_encode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1327:10
function json_encode(mixed $value, int $flags = 0, int $depth = 512) {}

  call to echo - Multilingual.php:293:8
                echo json_encode($response);



ERROR: TaintedTextWithQuotes - Multilingual.php:493:8 - Detected tainted text with possible quotes (see https://psalm.dev/274)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  mysqli_fetch_array - Multilingual.php:133:15
                                if($row = mysqli_fetch_array($result)){

  $row - Multilingual.php:310:9
                while($row = mysqli_fetch_array($result)){

  $row['element_label'] - Multilingual.php:312:59
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  concat - Multilingual.php:312:59
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  call to strip_tags - Multilingual.php:312:59
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  strip_tags#1 - Multilingual.php:312:59
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  strip_tags - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:767:69
function strip_tags(string $string, ?string $allowed_tags = null) : string {}

  $response['defaults'] - Multilingual.php:312:4
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  $response - Multilingual.php:312:4
                        $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '<br>');

  $response - Multilingual.php:489:3
                $response['exist'] = $this->updateLangVar($data);

  $response - Multilingual.php:490:3
                $response['table'] = $metaDataTableName;

  call to json_encode - Multilingual.php:493:20
                echo json_encode($response);

  json_encode#1 - Multilingual.php:493:20
                echo json_encode($response);

  json_encode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1327:10
function json_encode(mixed $value, int $flags = 0, int $depth = 512) {}

  call to echo - Multilingual.php:493:8
                echo json_encode($response);



ERROR: TaintedHtml - Multilingual.php:516:10 - Detected tainted HTML (see https://psalm.dev/245)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  REDCap::getData - ../../redcap_v13.2.1/ExternalModules/psalm/stubs/REDCap.phpstub:8:21
    static function getData(){}

  call to json_decode - Multilingual.php:513:23
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  json_decode#1 - Multilingual.php:513:23
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  json_decode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1317:10
function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) {}

  $tmp - Multilingual.php:513:4
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  $tmp[0] - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  $tmp[0][$langVar] - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  call to json_encode - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  json_encode#1 - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  json_encode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1327:10
function json_encode(mixed $value, int $flags = 0, int $depth = 512) {}

  call to echo - Multilingual.php:516:10
                                echo json_encode($tmp[0][$langVar]);



ERROR: TaintedTextWithQuotes - Multilingual.php:516:10 - Detected tainted text with possible quotes (see https://psalm.dev/274)
This is generally resolved by finding the simplest highlighted variable in the trace below (ideally a short string)
and wrapping it in htmlspecialchars($taintedString, ENT_QUOTES). In REDCap version TBD, a $module->escape() method
was added that avoids boilerplate in more complex cases by recursively escaping arrays and preserving primitive types.
It will become the recommendation once most institutions update to that REDCap version.
On older REDCap versions, the escape() method can be used now by copying it into your module class 
from <newer-redcap-version-source>/ExternalModules/classes/ExternalModules.php.

  REDCap::getData - ../../redcap_v13.2.1/ExternalModules/psalm/stubs/REDCap.phpstub:8:21
    static function getData(){}

  call to json_decode - Multilingual.php:513:23
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  json_decode#1 - Multilingual.php:513:23
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  json_decode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1317:10
function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) {}

  $tmp - Multilingual.php:513:4
                        $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true);

  $tmp[0] - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  $tmp[0][$langVar] - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  call to json_encode - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  json_encode#1 - Multilingual.php:516:22
                                echo json_encode($tmp[0][$langVar]);

  json_encode - ../../redcap_v13.2.1/ExternalModules/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1327:10
function json_encode(mixed $value, int $flags = 0, int $depth = 512) {}

  call to echo - Multilingual.php:516:10
                                echo json_encode($tmp[0][$langVar]);



ERROR: TaintedSql - Multilingual.php:647:21 - Detected tainted SQL (see https://psalm.dev/244)
To resolve this, use the $module->query() method and pass the variable highlighted at the last step of the trace
as a parameter via the second argument to the query() method (for details, see the documentation for this method).

  $_GET
    <no known location>

  $_GET['form'] - multilingualPDF.php:47:65
        $metadata = $module->getMetaData(intval(intval($_GET['pid'])), $_GET['form']);

  call to CMH\Multilingual\Multilingual::getMetaData - multilingualPDF.php:47:65
        $metadata = $module->getMetaData(intval(intval($_GET['pid'])), $_GET['form']);

  CMH\Multilingual\Multilingual::getMetaData#2 - Multilingual.php:639:50
        public function getMetaData($project_id = NULL, $form = NULL){

  $form - Multilingual.php:639:50
        public function getMetaData($project_id = NULL, $form = NULL){

  concat - Multilingual.php:645:15
                        . ($form ? " AND form_name = '" . $form . "'" : "") .

  concat - Multilingual.php:645:15
                        . ($form ? " AND form_name = '" . $form . "'" : "") .

  concat - Multilingual.php:643:8
                $q = "SELECT * FROM redcap_metadata
                        WHERE project_id = " . intval($project_id)
                        . ($form ? " AND form_name = '" . $form . "'" : "") .

  concat - Multilingual.php:643:8
                $q = "SELECT * FROM redcap_metadata
                        WHERE project_id = " . intval($project_id)
                        . ($form ? " AND form_name = '" . $form . "'" : "") .
                        " ORDER BY field_order";

  $q - Multilingual.php:643:3
                $q = "SELECT * FROM redcap_metadata

  call to db_query - Multilingual.php:647:21
                $query = db_query($q);



ERROR: TaintedHeader - multilingualPDF.php:126:9 - Detected tainted header (see https://psalm.dev/256)

  $_GET
    <no known location>

  $_GET['instance'] - multilingualPDF.php:126:335
        header('Location:' . APP_PATH_WEBROOT . "PDF" . DS . "index_multilingual_$random.php?pid=" . intval($_GET['pid']) . (isset($_GET['form']) ? "&page=" . $_GET['form'] : '') . "&id=" . $_GET['id'] . (isset($_GET['event_id']) ? "&event_id=" . $_GET['event_id'] : '') . (isset($_GET['instance']) && $_GET['instance'] > 1 ? "&instance=" . $_GET['instance'] : ''));

  concat - multilingualPDF.php:126:320
        header('Location:' . APP_PATH_WEBROOT . "PDF" . DS . "index_multilingual_$random.php?pid=" . intval($_GET['pid']) . (isset($_GET['form']) ? "&page=" . $_GET['form'] : '') . "&id=" . $_GET['id'] . (isset($_GET['event_id']) ? "&event_id=" . $_GET['event_id'] : '') . (isset($_GET['instance']) && $_GET['instance'] > 1 ? "&instance=" . $_GET['instance'] : ''));

  concat - multilingualPDF.php:126:9
        header('Location:' . APP_PATH_WEBROOT . "PDF" . DS . "index_multilingual_$random.php?pid=" . intval($_GET['pid']) . (isset($_GET['form']) ? "&page=" . $_GET['form'] : '') . "&id=" . $_GET['id'] . (isset($_GET['event_id']) ? "&event_id=" . $_GET['event_id'] : '') . (isset($_GET['instance']) && $_GET['instance'] > 1 ? "&instance=" . $_GET['instance'] : ''));

  call to header - multilingualPDF.php:126:9
        header('Location:' . APP_PATH_WEBROOT . "PDF" . DS . "index_multilingual_$random.php?pid=" . intval($_GET['pid']) . (isset($_GET['form']) ? "&page=" . $_GET['form'] : '') . "&id=" . $_GET['id'] . (isset($_GET['event_id']) ? "&event_id=" . $_GET['event_id'] : '') . (isset($_GET['instance']) && $_GET['instance'] > 1 ? "&instance=" . $_GET['instance'] : ''));



------------------------------
10 errors found
------------------------------

Checks took 15.19 seconds and used 311.308MB of memory
Psalm was able to infer types for 55.9509% of the codebase


---------------------------------------------------------------------------------------------

Please review the results above, consider any WARNINGs, and address any ERRORs.
Solutions to ERRORs should also be applied in comparable scenarios throughout the codebase,
as this scan is not capable of finding all potential vulnerabilities.

# 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions