mirror of
https://github.com/hwchase17/langchain
synced 2024-11-06 03:20:49 +00:00
Replace JIRA Arbitrary Code Execution vulnerability with finer grain API wrapper (#6992)
This fixes #4833 and the critical vulnerability
https://nvd.nist.gov/vuln/detail/CVE-2023-34540
Previously, the JIRA API Wrapper had a mode that simply pipelined user
input into an `exec()` function.
[The intended use of the 'other' mode is to cover any of Atlassian's API
that don't have an existing
interface](cc33bde74f/langchain/tools/jira/prompt.py (L24)
)
Fortunately all of the [Atlassian JIRA API methods are subfunctions of
their `Jira`
class](https://atlassian-python-api.readthedocs.io/jira.html), so this
implementation calls these subfunctions directly.
As well as passing a string representation of the function to call, the
implementation flexibly allows for optionally passing args and/or
keyword-args. These are given as part of the dictionary input. Example:
```
{
"function": "update_issue_field", #function to execute
"args": [ #list of ordered args similar to other examples in this JiraAPIWrapper
"key",
{"summary": "New summary"}
],
"kwargs": {} #dict of key value keyword-args pairs
}
```
the above is equivalent to `self.jira.update_issue_field("key",
{"summary": "New summary"})`
Alternate query schema designs are welcome to make querying easier
without passing and evaluating arbitrary python code. I considered
parsing (without evaluating) input python code and extracting the
function, args, and kwargs from there and then pipelining them into the
callable function via `*f(args, **kwargs)` - but this seemed more
direct.
@vowelparrot @dev2049
---------
Co-authored-by: Jamal Rahman <jamal.rahman@builder.ai>
This commit is contained in:
parent
61938a02a1
commit
a2f191a322
@ -25,11 +25,12 @@ JIRA_CATCH_ALL_PROMPT = """
|
|||||||
This tool is a wrapper around atlassian-python-api's Jira API.
|
This tool is a wrapper around atlassian-python-api's Jira API.
|
||||||
There are other dedicated tools for fetching all projects, and creating and searching for issues,
|
There are other dedicated tools for fetching all projects, and creating and searching for issues,
|
||||||
use this tool if you need to perform any other actions allowed by the atlassian-python-api Jira API.
|
use this tool if you need to perform any other actions allowed by the atlassian-python-api Jira API.
|
||||||
The input to this tool is line of python code that calls a function from atlassian-python-api's Jira API
|
The input to this tool is a dictionary specifying a function from atlassian-python-api's Jira API,
|
||||||
For example, to update the summary field of an issue, you would pass in the following string:
|
as well as a list of arguments and dictionary of keyword arguments to pass into the function.
|
||||||
self.jira.update_issue_field(key, {{"summary": "New summary"}})
|
For example, to get all the users in a group, while increasing the max number of results to 100, you would
|
||||||
|
pass in the following dictionary: {{"function": "get_all_users_from_group", "args": ["group"], "kwargs": {{"limit":100}} }}
|
||||||
or to find out how many projects are in the Jira instance, you would pass in the following string:
|
or to find out how many projects are in the Jira instance, you would pass in the following string:
|
||||||
self.jira.projects()
|
{{"function": "projects"}}
|
||||||
For more information on the Jira API, refer to https://atlassian-python-api.readthedocs.io/jira.html
|
For more information on the Jira API, refer to https://atlassian-python-api.readthedocs.io/jira.html
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -188,10 +188,15 @@ class JiraAPIWrapper(BaseModel):
|
|||||||
return self.confluence.create_page(**dict(params))
|
return self.confluence.create_page(**dict(params))
|
||||||
|
|
||||||
def other(self, query: str) -> str:
|
def other(self, query: str) -> str:
|
||||||
context = {"self": self}
|
try:
|
||||||
exec(f"result = {query}", context)
|
import json
|
||||||
result = context["result"]
|
except ImportError:
|
||||||
return str(result)
|
raise ImportError(
|
||||||
|
"json is not installed. Please install it with `pip install json`"
|
||||||
|
)
|
||||||
|
params = json.loads(query)
|
||||||
|
jira_function = getattr(self.jira, params["function"])
|
||||||
|
return jira_function(*params.get("args", []), **params.get("kwargs", {}))
|
||||||
|
|
||||||
def run(self, mode: str, query: str) -> str:
|
def run(self, mode: str, query: str) -> str:
|
||||||
if mode == "jql":
|
if mode == "jql":
|
||||||
|
@ -41,3 +41,24 @@ def test_create_confluence_page() -> None:
|
|||||||
output = jira.run("create_page", create_page_dict)
|
output = jira.run("create_page", create_page_dict)
|
||||||
assert "type" in output
|
assert "type" in output
|
||||||
assert "page" in output
|
assert "page" in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_other() -> None:
|
||||||
|
"""Non-exhaustive test for accessing other JIRA API methods"""
|
||||||
|
jira = JiraAPIWrapper()
|
||||||
|
issue_create_dict = """
|
||||||
|
{
|
||||||
|
"function":"issue_create",
|
||||||
|
"kwargs": {
|
||||||
|
"fields": {
|
||||||
|
"summary": "Test Summary",
|
||||||
|
"description": "Test Description",
|
||||||
|
"issuetype": {"name": "Bug"},
|
||||||
|
"project": {"key": "TP"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
output = jira.run("other", issue_create_dict)
|
||||||
|
assert "id" in output
|
||||||
|
assert "key" in output
|
||||||
|
Loading…
Reference in New Issue
Block a user