Replacing unsafe eval()
with json.loads()
to fix known vulnerability.
#1890
+1
−1
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
PrivateGPT
usedeval()
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 endpoint
can be predicted and manipulated.In
./private_gpt/components/llm/custom/sagemaker.py
'sSagemakerLLM
class'scomplete()
, we can see a method used to chat with remoteAWS Sagemaker LLM endpoint
AWS Sagemaker
is a ML platform of AWS, where user can deploy their ML projects including LLMs, In this case, this method is using AWS nativeboto3
SDK for us to chat with our remote AWS Sagemaker LLM endpointclass SagemakerLLM -> complete()
Firstly, the process updates the
self.generate_kwargs
dictionary 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 thekwargs
dictionary to determine if the input prompt text requires formatting; ifis_formatted
isFalse
, it calls theself.completion_to_prompt
method 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_endpoint
method, 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 theeval
function is used to convert this string into a dictionary.However, as we can see in the
Process Response
,privateGPT
usedeval()
to load remoteJSON format response
(unlike the brotherstream_complete
method), 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 Prompt
via 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_service
which imported fromprivategpt/server/chat_service.py
'sclass ChatService
; Thestreaming=False
was also register inclass ChatService
and also in theprivateGPT/server/chat/chat_router
, which functioned as aOpenAI-alike
endpoint/To setup our
privateGPT
we will need to register a application of Sagemaker in AWS, usingSagemaker jampstart
and etc, After logging into AWS inaws-cli
, we need to create asettings-sagemaker.yaml
that contains youAWS Sagemaker endpoint
informations.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
, aOpenAI
alike endpoint is also start when we usepoetry run python -m private_gpt
to run theprivategpt
remote server; this endpoint provided us to direct remotely access the vulnerablesagemaker's
streaming-lesscomplete() -> CompletionResponse:
using theAWS sagemaker LLM
we can access using the tools such ascurl
orwget
and etc. API Reference ofprivateGPT
can 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 theprivateGPT
API-endpoint
Exploitability
The exploitability of this vulnerability hinges on the misuse of the
eval()
function within theSagemakerLLM
class'scomplete()
method in theprivate_gpt
application. 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_gpt
application 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_gpt
application 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_gpt
application and the AWS SageMaker endpoint.