@@ -34,8 +34,8 @@ def test_basic(self):
34
34
35
35
@skipUnlessDBFeature ('validates_explain_options' )
36
36
def test_unknown_options (self ):
37
- with self .assertRaisesMessage (ValueError , ' Unknown options: test, test2' ):
38
- Tag .objects .all ().explain (test = 1 , test2 = 1 )
37
+ with self .assertRaisesMessage (ValueError , " Unknown options: TEST, TEST2" ):
38
+ Tag .objects .all ().explain (** { "TEST" : 1 , "TEST2" : 1 } )
39
39
40
40
def test_unknown_format (self ):
41
41
msg = 'DOES NOT EXIST is not a recognized format.'
@@ -68,6 +68,35 @@ def test_postgres_options(self):
68
68
option = '{} {}' .format (name .upper (), 'true' if value else 'false' )
69
69
self .assertIn (option , captured_queries [0 ]['sql' ])
70
70
71
+ def test_option_sql_injection (self ):
72
+ qs = Tag .objects .filter (name = "test" )
73
+ options = {"SUMMARY true) SELECT 1; --" : True }
74
+ msg = "Invalid option name: 'SUMMARY true) SELECT 1; --'"
75
+ with self .assertRaisesMessage (ValueError , msg ):
76
+ qs .explain (** options )
77
+
78
+ def test_invalid_option_names (self ):
79
+ qs = Tag .objects .filter (name = "test" )
80
+ tests = [
81
+ 'opt"ion' ,
82
+ "o'ption" ,
83
+ "op`tion" ,
84
+ "opti on" ,
85
+ "option--" ,
86
+ "optio\t n" ,
87
+ "o\n ption" ,
88
+ "option;" ,
89
+ "你 好" ,
90
+ # [] are used by MSSQL.
91
+ "option[" ,
92
+ "option]" ,
93
+ ]
94
+ for invalid_option in tests :
95
+ with self .subTest (invalid_option ):
96
+ msg = f"Invalid option name: { invalid_option !r} "
97
+ with self .assertRaisesMessage (ValueError , msg ):
98
+ qs .explain (** {invalid_option : True })
99
+
71
100
@unittest .skipUnless (connection .vendor == 'mysql' , 'MySQL specific' )
72
101
def test_mysql_text_to_traditional (self ):
73
102
# Ensure these cached properties are initialized to prevent queries for
0 commit comments