-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python: Add Gradio models #16135
Python: Add Gradio models #16135
Conversation
Hi team - I added example tests. Please let me know if anything could be improved! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry we have taken so long to get to this. Here is a first round of comments. Since this is targeting the main tree directly, I should also go through and check the modelling properly, so there may be a second round.
I included a way to convert one of your tests to inline; we could probably do the other one also.
this = call.getKeywordParameter("inputs").getASuccessor().getAValueReachingSink() | ||
or | ||
this = call.getParameter(1).getASuccessor().getAValueReachingSink() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getASuccessor
seems overly general, I think you would always want getASubscript
. Did you observe other relevant labels here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed getASuccessor to getASubscript in 944f884. What do you mean by relevant labels?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getASucessor
is asking for any successor in the directed labelled graph that is the API graph. That is, follow an edge no matter what label it has. I believe that, in your situation, you only want the edges labelled subscript
. I was asking if you had seen a need to follow an edge with a different label.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested the query with both getASucessor
and getASubscript
, and I see the results are the same. Like you said, I think I need only the edges labelled subscript
, so let's go with that
Thank you for the review @yoff! I addressed your comments.
Where did you make this change? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for making the simplifications. They have now enabled new ones..
import python | ||
import semmle.python.dataflow.new.RemoteFlowSources | ||
|
||
from RemoteFlowSource rfs | ||
select rfs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test can be made inline in the following way:
import python | |
import semmle.python.dataflow.new.RemoteFlowSources | |
from RemoteFlowSource rfs | |
select rfs | |
import python | |
import semmle.python.dataflow.new.RemoteFlowSources | |
import TestUtilities.InlineExpectationsTest | |
private import semmle.python.dataflow.new.internal.PrintNode | |
module SourceTest implements TestSig { | |
string getARelevantTag() { result = "source" } | |
predicate hasActualResult(Location location, string element, string tag, string value) { | |
exists(location.getFile().getRelativePath()) and | |
exists(RemoteFlowSource rfs | | |
location = rfs.getLocation() and | |
element = rfs.toString() and | |
value = prettyNode(rfs) and | |
tag = "source" | |
) | |
} | |
} | |
import MakeTest<SourceTest> |
You will then have to adjust the test files by adding annotations (eg. line 15 of source_test.py
becomes def greet(name): # $ source=name
, the test failures will tell you what to add where) and making source_test.expected
empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I added the annotations and fixed the test files in d6acea1. I'm unsure how to test the taint step though - is it fine as it is now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that looks good. Testing the taint step is a bit more difficult because it is private
. We could add provenance to it and test it that way, but we can leave this for later.
In |
Compilation fails because you need to format the code: https://github.com/github/codeql/actions/runs/9002043454/job/24729510202?pr=16135#step:5:8 |
Co-authored-by: yoff <[email protected]>
Fixed the test files and formatting 🚀 |
The failing tests suggest that you need to merge in main (this is partly because we were so long getting to review this, sorry). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One question about the modelling, otherwise this looks fine.
"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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all these vulnerable? I quickly checked a few of them and it looks like:
HighlightedText
only allows the user to specify substrings of a given textColorPicker
only passes on hex stringsAnnotatedImage
does not accept user input at all
We should probably only include actually vulnerable inputs here in order to avoid the query getting noisy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s the event listeners that take untrusted user input, so, for example, gradio.AnnotatedImage.select(fn, inputs, outputs)
(see docs) and that's what we model here.
To clarify - with the above models, we look for any event listeners of the listed classes. For example, gr.Button
has only one, click()
(see this example, which asks for a user's name and displays it). Side note that if an event listener does not exist for a given class, CodeQL doesn't (can't) match it (for example there is no gr.Button.select()
). I found this way of modeling to be the most succinct and it doesn't slow performance, but I'm open to feedback around it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is fine to model situations that will never match, I was more worried about false positives. But on reflection, I think this is fine to start; we can refine it if we actually encounter any problems..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've already found a few vulnerabilities using these models, including in stable-diffusion-webui (120k stars):
https://securitylab.github.com/advisories/GHSL-2024-010_stable-diffusion-webui/
https://securitylab.github.com/advisories/GHSL-2024-019_GHSL-2024-024_kohya_ss/
To be fair, I tested the AnnotatedImage.select()
event listener (and several other event listeners on the list), and it does take user input, but it's not very popular to use, so I haven't actually seen vulnerabilities around it. Most of the vulnerabilities happen with Button.click()
(including the 7 vulns I linked to above). I think there shouldn't be many false positives here, but I'll be happy to help if anything needs refining.
@yoff I just updated my branch to main and rerun the tests, but both return |
Is your local CLI up-to-date? The tests run on our CI infra structure reporting the expected diff. |
You're right, I needed to update the CLI. There was a slight change in the results of the taint step test, likely due to the new CLI, so I updated the results in 34c4479. Is it okay that the test results contain |
Nothing to be done, this is what it should look like :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just make the modelling classes private so that we can change them later without the whole deprecation dance (I guess none of these are meant to be depended on by users), then it looks good to go :-)
Co-authored-by: yoff <[email protected]>
@yoff Added your proposed changes 🚀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Gradio is the go-to web framework for creating machine learning demos. This pull request adds models for the Gradio framework.
Looking forward to your feedback!