Skip to content

Commit 1129925

Browse files
Add change note
1 parent 84d6956 commit 1129925

File tree

2 files changed

+97
-80
lines changed

2 files changed

+97
-80
lines changed

python/ql/lib/semmle/python/frameworks/Gradio.qll

Lines changed: 93 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,129 +16,142 @@ module Gradio {
1616
/**
1717
* The event handlers in Gradio, which take untrusted data.
1818
*/
19-
2019
class GradioInput extends API::CallNode {
21-
GradioInput() { this = API::moduleImport("gradio")
22-
.getMember([
23-
"Button", "Textbox", "UploadButton", "Slider",
24-
"JSON", "HTML", "Markdown", "File",
25-
"AnnotatedImage", "Audio", "BarPlot", "Chatbot", "Checkbox",
26-
"CheckboxGroup", "ClearButton", "Code", "ColorPicker", "Dataframe",
27-
"Dataset", "DownloadButton", "Dropdown", "DuplicateButton", "FileExplorer",
28-
"Gallery", "HighlightedText", "Image", "ImageEditor", "Label", "LinePlot",
29-
"LoginButton", "LogoutButton", "Model3D", "Number", "ParamViewer",
30-
"Plot", "Radio", "ScatterPlot", "SimpleImage", "State", "Video"])
31-
.getReturn()
32-
.getMember([
33-
"change", "input", "click", "submit",
34-
"edit", "clear", "play", "pause", "stop", "end", "start_recording",
35-
"pause_recording", "stop_recording", "focus", "blur",
36-
"upload", "release", "select", "stream", "like", "load",
37-
"like", "key_up",])
38-
.getACall()
39-
}
40-
20+
GradioInput() {
21+
this =
22+
API::moduleImport("gradio")
23+
.getMember([
24+
"Button", "Textbox", "UploadButton", "Slider", "JSON", "HTML", "Markdown", "File",
25+
"AnnotatedImage", "Audio", "BarPlot", "Chatbot", "Checkbox", "CheckboxGroup",
26+
"ClearButton", "Code", "ColorPicker", "Dataframe", "Dataset", "DownloadButton",
27+
"Dropdown", "DuplicateButton", "FileExplorer", "Gallery", "HighlightedText",
28+
"Image", "ImageEditor", "Label", "LinePlot", "LoginButton", "LogoutButton",
29+
"Model3D", "Number", "ParamViewer", "Plot", "Radio", "ScatterPlot", "SimpleImage",
30+
"State", "Video"
31+
])
32+
.getReturn()
33+
.getMember([
34+
"change", "input", "click", "submit", "edit", "clear", "play", "pause", "stop",
35+
"end", "start_recording", "pause_recording", "stop_recording", "focus", "blur",
36+
"upload", "release", "select", "stream", "like", "load", "like", "key_up",
37+
])
38+
.getACall()
4139
}
40+
}
4241

43-
/**
44-
* The high-level gradio.Interface and gradio.ChatInterface classes, which take untrusted data.
45-
*/
46-
class GradioInterface extends API::CallNode {
47-
GradioInterface() { this = API::moduleImport("gradio").getMember(["Interface", "ChatInterface"]).getACall() }
42+
/**
43+
* The high-level gradio.Interface and gradio.ChatInterface classes, which take untrusted data.
44+
*/
45+
class GradioInterface extends API::CallNode {
46+
GradioInterface() {
47+
this = API::moduleImport("gradio").getMember(["Interface", "ChatInterface"]).getACall()
4848
}
49+
}
4950

5051
/**
5152
* The `inputs` parameters in Gradio event handlers, that are lists and are sources of untrusted data.
5253
* This model allows tracking each element list back to source, f.ex. `gr.Textbox(...)`.
5354
*/
5455
class GradioInputList extends RemoteFlowSource::Range {
5556
GradioInputList() {
56-
exists(API::CallNode call |
57-
(call instanceof GradioInput
58-
or
59-
call instanceof GradioInterface)
60-
and
57+
exists(API::CallNode call |
58+
(
59+
call instanceof GradioInput
60+
or
61+
call instanceof GradioInterface
62+
) and
6163
// limit only to lists of parameters given to `inputs`.
62-
((call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
64+
(
65+
(
66+
call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
6367
or
64-
call.getParameter(1).asSink().asCfgNode() instanceof ListNode)
65-
and
66-
(this = call.getKeywordParameter("inputs").getASuccessor().getAValueReachingSink()
67-
or
68-
this = call.getParameter(1).getASuccessor().getAValueReachingSink()))
69-
)
68+
call.getParameter(1).asSink().asCfgNode() instanceof ListNode
69+
) and
70+
(
71+
this = call.getKeywordParameter("inputs").getASuccessor().getAValueReachingSink()
72+
or
73+
this = call.getParameter(1).getASuccessor().getAValueReachingSink()
74+
)
75+
)
76+
)
7077
}
71-
override string getSourceType() { result = "Gradio untrusted input" }
72-
7378

79+
override string getSourceType() { result = "Gradio untrusted input" }
7480
}
7581

7682
/**
7783
* The `inputs` parameters in Gradio event handlers, that are not lists and are sources of untrusted data.
7884
*/
7985
class GradioInputParameter extends RemoteFlowSource::Range {
8086
GradioInputParameter() {
81-
exists(API::CallNode call |
82-
(call instanceof GradioInput
83-
or
84-
call instanceof GradioInterface)
85-
86-
and
87-
(this = call.getKeywordParameter("fn").getParameter(_).asSource()
88-
or
89-
this = call.getParameter(0).getParameter(_).asSource())
90-
91-
and
92-
// exclude lists of parameters given to `inputs`
93-
not call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
94-
and
95-
not call.getParameter(1).asSink().asCfgNode() instanceof ListNode
87+
exists(API::CallNode call |
88+
(
89+
call instanceof GradioInput
90+
or
91+
call instanceof GradioInterface
92+
) and
93+
(
94+
this = call.getKeywordParameter("fn").getParameter(_).asSource()
95+
or
96+
this = call.getParameter(0).getParameter(_).asSource()
97+
) and
98+
// exclude lists of parameters given to `inputs`
99+
not call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode and
100+
not call.getParameter(1).asSink().asCfgNode() instanceof ListNode
96101
)
97102
}
98-
override string getSourceType() { result = "Gradio untrusted input" }
99-
}
103+
104+
override string getSourceType() { result = "Gradio untrusted input" }
105+
}
100106

101107
/**
102108
* The `inputs` parameters in Gradio decorators to event handlers, that are sources of untrusted data.
103109
*/
104-
class GradioInputDecorator extends RemoteFlowSource::Range {
110+
class GradioInputDecorator extends RemoteFlowSource::Range {
105111
GradioInputDecorator() {
106112
exists(API::CallNode call |
107-
(call instanceof GradioInput or call instanceof GradioInterface)
108-
and
113+
(call instanceof GradioInput or call instanceof GradioInterface) and
109114
this = call.getReturn().getACall().getParameter(0).getParameter(_).asSource()
110115
)
111116
}
112-
override string getSourceType() { result = "Gradio untrusted input" }
113-
}
117+
118+
override string getSourceType() { result = "Gradio untrusted input" }
119+
}
114120

115121
/**
116122
* Extra taint propagation for tracking `inputs` parameters in Gradio event handlers, that are lists.
117123
*/
118124
private class ListTaintStep extends TaintTracking::AdditionalTaintStep {
119125
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
120126
exists(API::CallNode node |
121-
(node instanceof GradioInput
122-
or
123-
node instanceof GradioInterface)
124-
and
125-
// handle cases where there are multiple arguments passed as a list to `inputs`
126-
((
127-
(node.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
128-
or
129-
node.getParameter(1).asSink().asCfgNode() instanceof ListNode)
130-
and
131-
exists(int i |
132-
(nodeTo = node.getParameter(0).getParameter(i).asSource()
133-
or
134-
nodeTo = node.getKeywordParameter("fn").getParameter(i).asSource())
135-
and
136-
(nodeFrom.asCfgNode() = node.getKeywordParameter("inputs").asSink().asCfgNode().(ListNode).getElement(i)
127+
(
128+
node instanceof GradioInput
137129
or
138-
nodeFrom.asCfgNode() = node.getParameter(1).asSink().asCfgNode().(ListNode).getElement(i))))
130+
node instanceof GradioInterface
131+
) and
132+
// handle cases where there are multiple arguments passed as a list to `inputs`
133+
(
134+
(
135+
node.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
136+
or
137+
node.getParameter(1).asSink().asCfgNode() instanceof ListNode
138+
) and
139+
exists(int i |
140+
(
141+
nodeTo = node.getParameter(0).getParameter(i).asSource()
142+
or
143+
nodeTo = node.getKeywordParameter("fn").getParameter(i).asSource()
144+
) and
145+
(
146+
nodeFrom.asCfgNode() =
147+
node.getKeywordParameter("inputs").asSink().asCfgNode().(ListNode).getElement(i)
148+
or
149+
nodeFrom.asCfgNode() =
150+
node.getParameter(1).asSink().asCfgNode().(ListNode).getElement(i)
151+
)
152+
)
139153
)
140154
)
141155
}
142156
}
143-
144157
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added models of `gradio` PyPI package.

0 commit comments

Comments
 (0)