mirror of
https://github.com/github/codeql.git
synced 2026-04-06 07:34:00 +02:00
124 lines
4.6 KiB
Plaintext
124 lines
4.6 KiB
Plaintext
/**
|
|
* Provides classes modeling security-relevant aspects of the `gradio` PyPI package.
|
|
* See https://pypi.org/project/gradio/.
|
|
*/
|
|
|
|
import python
|
|
import semmle.python.dataflow.new.RemoteFlowSources
|
|
import semmle.python.dataflow.new.TaintTracking
|
|
import semmle.python.ApiGraphs
|
|
|
|
/**
|
|
* Provides models for the `gradio` PyPI package.
|
|
* See https://pypi.org/project/gradio/.
|
|
*/
|
|
module Gradio {
|
|
/**
|
|
* The event handlers, Interface and gradio.ChatInterface classes, which take untrusted data.
|
|
*/
|
|
private class GradioInput extends API::CallNode {
|
|
GradioInput() {
|
|
this =
|
|
API::moduleImport("gradio")
|
|
.getMember([
|
|
"Button", "Textbox", "UploadButton", "Slider", "JSON", "HTML", "Markdown", "File",
|
|
"AnnotatedImage", "Audio", "BarPlot", "Chatbot", "Checkbox", "CheckboxGroup",
|
|
"ClearButton", "Code", "ColorPicker", "Dataframe", "Dataset", "DownloadButton",
|
|
"Dropdown", "DuplicateButton", "FileExplorer", "Gallery", "HighlightedText",
|
|
"Image", "ImageEditor", "Label", "LinePlot", "LoginButton", "LogoutButton",
|
|
"Model3D", "Number", "ParamViewer", "Plot", "Radio", "ScatterPlot", "SimpleImage",
|
|
"State", "Video"
|
|
])
|
|
.getReturn()
|
|
.getMember([
|
|
"change", "input", "click", "submit", "edit", "clear", "play", "pause", "stop",
|
|
"end", "start_recording", "pause_recording", "stop_recording", "focus", "blur",
|
|
"upload", "release", "select", "stream", "like", "load", "key_up",
|
|
])
|
|
.getACall()
|
|
or
|
|
this = API::moduleImport("gradio").getMember(["Interface", "ChatInterface"]).getACall()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The `inputs` parameters in Gradio event handlers, that are lists and are sources of untrusted data.
|
|
* This model allows tracking each element list back to source, f.ex. `gr.Textbox(...)`.
|
|
*/
|
|
private class GradioInputList extends RemoteFlowSource::Range {
|
|
GradioInputList() {
|
|
exists(GradioInput call |
|
|
// limit only to lists of parameters given to `inputs`.
|
|
(
|
|
(
|
|
call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
|
|
or
|
|
call.getParameter(1).asSink().asCfgNode() instanceof ListNode
|
|
) and
|
|
(
|
|
this = call.getKeywordParameter("inputs").getASubscript().getAValueReachingSink()
|
|
or
|
|
this = call.getParameter(1).getASubscript().getAValueReachingSink()
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
override string getSourceType() { result = "Gradio untrusted input" }
|
|
}
|
|
|
|
/**
|
|
* The `inputs` parameters in Gradio event handlers, that are not lists and are sources of untrusted data.
|
|
*/
|
|
private class GradioInputParameter extends RemoteFlowSource::Range {
|
|
GradioInputParameter() {
|
|
exists(GradioInput call |
|
|
this = call.getParameter(0, "fn").getParameter(_).asSource() and
|
|
// exclude lists of parameters given to `inputs`
|
|
not call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode and
|
|
not call.getParameter(1).asSink().asCfgNode() instanceof ListNode
|
|
)
|
|
}
|
|
|
|
override string getSourceType() { result = "Gradio untrusted input" }
|
|
}
|
|
|
|
/**
|
|
* The `inputs` parameters in Gradio decorators to event handlers, that are sources of untrusted data.
|
|
*/
|
|
private class GradioInputDecorator extends RemoteFlowSource::Range {
|
|
GradioInputDecorator() {
|
|
exists(GradioInput call |
|
|
this = call.getReturn().getACall().getParameter(0).getParameter(_).asSource()
|
|
)
|
|
}
|
|
|
|
override string getSourceType() { result = "Gradio untrusted input" }
|
|
}
|
|
|
|
/**
|
|
* Extra taint propagation for tracking `inputs` parameters in Gradio event handlers, that are lists.
|
|
*/
|
|
private class ListTaintStep extends TaintTracking::AdditionalTaintStep {
|
|
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
|
exists(GradioInput node |
|
|
// handle cases where there are multiple arguments passed as a list to `inputs`
|
|
(
|
|
(
|
|
node.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode
|
|
or
|
|
node.getParameter(1).asSink().asCfgNode() instanceof ListNode
|
|
) and
|
|
exists(int i | nodeTo = node.getParameter(0, "fn").getParameter(i).asSource() |
|
|
nodeFrom.asCfgNode() =
|
|
node.getKeywordParameter("inputs").asSink().asCfgNode().(ListNode).getElement(i)
|
|
or
|
|
nodeFrom.asCfgNode() =
|
|
node.getParameter(1).asSink().asCfgNode().(ListNode).getElement(i)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|