Replacing unsafe eval() with json.loads() to fix known vulnerability.#1890
Merged
imartinez merged 1 commit intozylon-ai:mainfrom Apr 30, 2024
Merged
Replacing unsafe eval() with json.loads() to fix known vulnerability.#1890imartinez merged 1 commit intozylon-ai:mainfrom
eval() with json.loads() to fix known vulnerability.#1890imartinez merged 1 commit intozylon-ai:mainfrom
Conversation
imartinez
approved these changes
Apr 30, 2024
Collaborator
imartinez
left a comment
There was a problem hiding this comment.
Thanks for the detailed report and fix!
Contributor
Author
|
@imartinez |
Collaborator
Sure, done! Now it says "The fix bounty is now up for grabs", in case you want to also claim it |
|
Does requesting a new git tag seems to be a reasonable request now? |
13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is for a fix for a reported possible RCE-resulting vulnerability that I reported on huntr.com; Since that
PrivateGPTusedeval()instead ofjson.loads()to load the remote-retrieved string into a dictionary, Python-OS-command injections payload can be parsed the response ofAWS Sagemaker LLM endpointcan be predicted and manipulated.In
./private_gpt/components/llm/custom/sagemaker.py'sSagemakerLLMclass'scomplete(), we can see a method used to chat with remoteAWS Sagemaker LLM endpointAWS Sagemakeris a ML platform of AWS, where user can deploy their ML projects including LLMs, In this case, this method is using AWS nativeboto3SDK for us to chat with our remote AWS Sagemaker LLM endpointclass SagemakerLLM -> complete()Firstly, the process updates the
self.generate_kwargsdictionary by setting the"stream"key's value toFalse, indicating that the text generation task will not utilize stream mode. It then checks the"formatted"key in thekwargsdictionary to determine if the input prompt text requires formatting; ifis_formattedisFalse, it calls theself.completion_to_promptmethod to format the prompt text accordingly. Next, it prepares the request parameters to be sent to the SageMaker endpoint, which includes the input prompt text, the"stream"parameter (set toFalse), and other inference parameters (self.inference_params). Using the AWS SDK (boto3 client)'sinvoke_endpointmethod, the process sends a request to the specified SageMaker model endpoint with the prepared parameters formatted as JSON. Finally, the response received from the SageMaker endpoint is read and decoded into a string, and theevalfunction is used to convert this string into a dictionary.However, as we can see in the
Process Response,privateGPTusedeval()to load remoteJSON format response(unlike the brotherstream_completemethod), which is extremely unsafe since attackers can inject python payloads in to the response_body of LLM by Manipulating the response of LLM the victim specifics in thesetting.yaml, LLM's safety may varies. However, since we can control theSystem Promptvia the built-in endpoint ofPrivateGPT, Controlling the response of LLM will be easy despite the LLM specifics.Source
By X-Referencing, we found that although most of applications in
privategpt/ui.py(The index webpage ofPrivateGPT) use the brotherstream_chat()that is registered underself._chat_servicewhich imported fromprivategpt/server/chat_service.py'sclass ChatService; Thestreaming=Falsewas also register inclass ChatServiceand also in theprivateGPT/server/chat/chat_router, which functioned as aOpenAI-alikeendpoint/To setup our
privateGPTwe will need to register a application of Sagemaker in AWS, usingSagemaker jampstartand etc, After logging into AWS inaws-cli, we need to create asettings-sagemaker.yamlthat contains youAWS Sagemaker endpointinformations.After that, we can start the server
When the server is started ,we can navigate to http://localhost:8001/ to use the Gradio UI or to http://localhost:8001/docs (API section) to try the API.
As we can see in the official docs of
privateGPT, aOpenAIalike endpoint is also start when we usepoetry run python -m private_gptto run theprivategptremote server; this endpoint provided us to direct remotely access the vulnerablesagemaker'sstreaming-lesscomplete() -> CompletionResponse:using theAWS sagemaker LLMwe can access using the tools such ascurlorwgetand etc. API Reference ofprivateGPTcan be view at [the official docs of privateGPT](https://docs.privategpt.dev/api-reference/api-reference/contextual-completions/prompt-completion-v-1-completions-post-stream)For example, this payload will trigger the vulnerable stream-less
complete()under theprivateGPTAPI-endpointExploitability
The exploitability of this vulnerability hinges on the misuse of the
eval()function within theSagemakerLLMclass'scomplete()method in theprivate_gptapplication. This function is notoriously unsafe for processing untrusted input because it interprets a string as Python code. In this case, the method receives a string from a remote AWS SageMaker LLM endpoint, which is expected to be in JSON format. The use ofeval()to parse this string into a dictionary introduces a significant security risk because it can execute arbitrary Python code contained within the response.An attacker can exploit this vulnerability by manipulating the response from the AWS SageMaker LLM endpoint to include malicious Python code. Since the
private_gptapplication treats the response as trustworthy and executes theeval()function on it, any Python code injected by the attacker would be executed by the application.The manipulation of the LLM response can be facilitated through several vectors:
Influence over the LLM's output through crafted inputs: The attacker can control the input to the LLM attackers
might influence the LLM to generate output that includes malicious code, LLM can be tricked into generating such
output.
Direct manipulation of the LLM response:
If the attacker has the ability to intercept or otherwise manipulate the network traffic between the
private_gptapplication and the AWS SageMaker endpoint, they could alter legitimate responses to include malicious code.Given that the vulnerable method is part of the functionality allowing interaction with the AWS SageMaker LLM endpoint, and considering the potential for attackers to either directly manipulate the LLM's response or influence its output through crafted inputs, Additionally the endpoint is expose since
uvicorn.run(app, host='0.0.0.0';, port=settings().server.port, log_config=None)is binding to all interfaces; the exploitability of this vulnerability is high and confident.Fixes
Mitigation strategies should include replacing the use of
eval()with a safer alternative such asjson.loads()for parsing JSON strings, implementing proper input validation and sanitization to prevent the LLM from generating malicious outputs, and using secure communication channels to protect the integrity of data in transit between theprivate_gptapplication and the AWS SageMaker endpoint.