@@ -94,11 +94,8 @@ public function __construct(
9494 public function get ($ app , $ lang = null , $ locale = null ) {
9595 return new LazyL10N (function () use ($ app , $ lang , $ locale ) {
9696 $ app = $ this ->appManager ->cleanAppId ($ app );
97- if ($ lang !== null ) {
98- $ lang = str_replace (['\0 ' , '/ ' , '\\' , '.. ' ], '' , $ lang );
99- }
100-
101- $ forceLang = $ this ->request ->getParam ('forceLanguage ' ) ?? $ this ->config ->getSystemValue ('force_language ' , false );
97+ $ lang = $ this ->cleanLanguage ($ lang );
98+ $ forceLang = $ this ->cleanLanguage ($ this ->request ->getParam ('forceLanguage ' )) ?? $ this ->config ->getSystemValue ('force_language ' , false );
10299 if (is_string ($ forceLang )) {
103100 $ lang = $ forceLang ;
104101 }
@@ -128,6 +125,29 @@ public function get($app, $lang = null, $locale = null) {
128125 });
129126 }
130127
128+ /**
129+ * Remove some invalid characters before using a string as a language
130+ *
131+ * @psalm-taint-escape callable
132+ * @psalm-taint-escape cookie
133+ * @psalm-taint-escape file
134+ * @psalm-taint-escape has_quotes
135+ * @psalm-taint-escape header
136+ * @psalm-taint-escape html
137+ * @psalm-taint-escape include
138+ * @psalm-taint-escape ldap
139+ * @psalm-taint-escape shell
140+ * @psalm-taint-escape sql
141+ * @psalm-taint-escape unserialize
142+ */
143+ private function cleanLanguage (?string $ lang ): ?string {
144+ if ($ lang === null ) {
145+ return null ;
146+ }
147+ $ lang = preg_replace ('/[^a-zA-Z0-9.;,=-]/ ' , '' , $ lang );
148+ return str_replace ('.. ' , '' , $ lang );
149+ }
150+
131151 /**
132152 * Check that $lang is an existing language and not null, otherwise return the language to use instead
133153 *
@@ -160,7 +180,7 @@ private function validateLanguage(string $app, ?string $lang): string {
160180 */
161181 public function findLanguage (?string $ appId = null ): string {
162182 // Step 1: Forced language always has precedence over anything else
163- $ forceLang = $ this ->request ->getParam ('forceLanguage ' ) ?? $ this ->config ->getSystemValue ('force_language ' , false );
183+ $ forceLang = $ this ->cleanLanguage ( $ this -> request ->getParam ('forceLanguage ' ) ) ?? $ this ->config ->getSystemValue ('force_language ' , false );
164184 if (is_string ($ forceLang )) {
165185 $ this ->requestLanguage = $ forceLang ;
166186 }
@@ -217,7 +237,7 @@ public function findLanguage(?string $appId = null): string {
217237
218238 public function findGenericLanguage (?string $ appId = null ): string {
219239 // Step 1: Forced language always has precedence over anything else
220- $ forcedLanguage = $ this ->request ->getParam ('forceLanguage ' ) ?? $ this ->config ->getSystemValue ('force_language ' , false );
240+ $ forcedLanguage = $ this ->cleanLanguage ( $ this -> request ->getParam ('forceLanguage ' ) ) ?? $ this ->config ->getSystemValue ('force_language ' , false );
221241 if ($ forcedLanguage !== false ) {
222242 return $ forcedLanguage ;
223243 }
@@ -412,7 +432,8 @@ public function getUserLanguage(?IUser $user = null): string {
412432 return $ language ;
413433 }
414434
415- if (($ forcedLanguage = $ this ->request ->getParam ('forceLanguage ' )) !== null ) {
435+ $ forcedLanguage = $ this ->cleanLanguage ($ this ->request ->getParam ('forceLanguage ' ));
436+ if ($ forcedLanguage !== null ) {
416437 return $ forcedLanguage ;
417438 }
418439
@@ -426,7 +447,7 @@ public function getUserLanguage(?IUser $user = null): string {
426447 }
427448 }
428449
429- return $ this ->request ->getParam ('forceLanguage ' ) ?? $ this ->config ->getSystemValueString ('default_language ' , 'en ' );
450+ return $ this ->cleanLanguage ( $ this -> request ->getParam ('forceLanguage ' ) ) ?? $ this ->config ->getSystemValueString ('default_language ' , 'en ' );
430451 }
431452
432453 /**
@@ -452,7 +473,7 @@ public function localeExists($locale) {
452473 * @throws LanguageNotFoundException
453474 */
454475 private function getLanguageFromRequest (?string $ app = null ): string {
455- $ header = $ this ->request ->getHeader ('ACCEPT_LANGUAGE ' );
476+ $ header = $ this ->cleanLanguage ( $ this -> request ->getHeader ('ACCEPT_LANGUAGE ' ) );
456477 if ($ header !== '' ) {
457478 $ available = $ this ->findAvailableLanguages ($ app );
458479
0 commit comments