- Blog
- Security Research
- Beyond the Bands: Exploiting TiTiler’s Expression Parser for Remote Code Execution
Beyond the Bands: Exploiting TiTiler’s Expression Parser for Remote Code Execution
A methodical analysis of TiTiler's API endpoints and its expression parser, leading to arbitrary Python code execution on the server.
As you probably already know XBOW achieved the distinction of Top 1 Hacker in the US last quarter, a feat attributed to the discovery of high-severity bugs within programs it has access to. This post outlines XBOW’s systematic approach to uncovering and exploiting a critical Remote Code Execution (RCE) vulnerability in one such program. While the program’s name remains undisclosed, its open-source nature allows for a detailed revelation of the arbitrary code execution steps undertaken by XBOW.
During the reconnaissance of this asset in scope of this HackerOne program, XBOW found it was TiTiler, a server for Cloud Optimized GeoTIFFs (COGs). Through a methodical analysis of TiTiler’s API endpoints and its expression parser, XBOW successfully executed arbitrary Python code on the server. This case study underscores the effectiveness of autonomous security testing and highlights the inherent dangers of insecure code evaluation in contemporary web applications. As a bonus, XBOW also found a different vulnerability allowing arbitrary file read, which will be the subject of our next post so stay tuned!
Reconnaissance and Initial Assessment
The process began with enumerating available endpoints by retrieving the application’s OpenAPI specification. This revealed that the application was running TiTiler, a dynamic tile server for Cloud Optimized GeoTIFFs (COGs), and that it exposed several endpoints accepting a url parameter, which is commonly susceptible to Server-Side Request Forgery (SSRF) if not handled securely.
Testing confirmed that the application performed outbound requests to attacker-controlled domains, validating the presence of SSRF. However, initial attempts to escalate this to arbitrary file read via file format or XML-based attacks (such as XXE) were unsuccessful due to format restrictions and error handling.
Identifying Deeper Attack Surface
Further analysis of the OpenAPI documentation highlighted endpoints accepting an expression parameter, described as supporting “band math.” XBOW identifies this parameter as a potential vector for code injection, depending on how expressions were parsed and executed.
Overcoming Input Validation Barriers
Initial attempts to inject malicious payloads into the expression parameter failed because the application required the url parameter to reference a valid TIFF file. To address this, XBOW quickly crafted a python script to generate minimal valid TIFF files, enabling further testing of the expression parser.
Probing the Expression Parser
With a valid TIFF in place, XBOW started poking around the expression parameter as a security researcher would do. First by confirming that simple expressions (eg: b1 band 1 reference) were evaluated correctly and then testing basic python payloads and even some sandbox escaping ones.
However, direct attempts at code injection (e.g., __import__('os').system('id')) resulted in errors, suggesting that the parser was not simply using Python’s eval() but was instead employing a more restricted or custom evaluation engine.
At this point, XBOW subsequently explored two distinct exploitation vectors: algorithm manipulation and expression injection.
For the algorithm vector, XBOW thought that the algorithm and algorithm_params parameters could end up being used to invoke a process or maybe even in a shell so, it tried several command injection payloads:
While this attack vector proved unsuccessful, it exemplified XBOW’s methodical approach to parameter and endpoint-specific vulnerability testing.
Discovery of a Critical Flaw
Back to the expression vector, XBOW decided to try similar payloads on other endpoints accepting an expression parameter which quickly paid out with a scent to follow:
With evidences that the expression was being parsed, XBOW hit the endpoint again, this time with a custom python script meant to try different alternative payloads:
This process, which might require significant time for a human pentester, even with the aid of AI copilots, was completed by XBOW in a matter of seconds, yielding a highly promising output. The /cog/crop/{minx},{miny},{maxx},{maxy}.{format} endpoint (e.g., /cog/crop/0,0,1,1.png) is indeed parsing the expression parameter, and the error messages are very different from the generic GDAL errors or simple “invalid syntax”.
Here is XBOW analysis of the output of the previous script:
Achieving Remote Code Execution
Now XBOW knows that python code is executed! Building on this discovery, XBOW constructed a payload to locate and invoke the system function, successfully returning a 200 response and so possible triggering command execution with the following payload
[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == '_wrap_close'][0].__init__.__globals__['system']('id') + b1*0
A 200 response and image output indicated that the payload had executed and the result was processed as expected.
Out-of-Band Verification
To conclusively verify code execution, XBOW used a payload that triggered an outbound HTTP request from the server using Python’s urllib module.
The request was observed in the attacker’s logs, confirming that arbitrary Python code execution was possible.
Exfiltrating Command Output
So the new plan is to exfiltrate the commands output using requests to its own server:
Unfortunately, the payload did not work and returned with the following error:
Something went wrong and the expression parser tried to parse ase64 as an integer. Undeterred by the error, XBOW turned it into the final exfiltration vector! If the parser returns the string literals that cannot be cast to integers, we just need to cast the output of our command execution to an integer: int(expression)
This method proved successful! Such a brilliant idea!
The error message returned to the client contained the output of the id command, providing direct evidence of successful RCE. This trace demonstrates a methodical, multi-stage approach to vulnerability discovery and exploitation in under 32 iterations and 12 minutes.
Root Cause Analysis
After XBOW’s automated exploitation, XBOW security team performed a manual investigation to pinpoint the underlying cause of the RCE vulnerability in TiTiler. The core issue traces back to TiTiler’s use of the rio-tiler library, which provides dynamic raster processing capabilities for Cloud Optimized GeoTIFFs. Under the hood, rio-tiler relies on the numexpr library to evaluate mathematical expressions provided by users through API parameters like expression.
The vulnerability arises from insufficient input validation in the evaluate function of numexpr. This function, if passed untrusted input, can allow arbitrary Python code execution—a classic code injection scenario. This issue was publicly disclosed as CVE-2023-39631, which describes how attackers can exploit the lack of input sanitization to execute code on numexpr host system.
Conclusion
The discovery of remote code execution in TiTiler’s expression parser highlights the real-world risks that can emerge when powerful input features are exposed without rigorous validation. By leveraging XBOW’s autonomous testing capabilities, we were able to systematically map the attack surface, identify subtle code execution pathways, and validate exploitation using both in-band and out-of-band techniques.
This case underscores the importance of scrutinizing any functionality that interprets user-supplied expressions or code—especially in applications handling complex data formats like GeoTIFFs. As attackers continue to look for creative ways to turn benign features into critical vulnerabilities, autonomous agents like XBOW are essential for staying ahead.
Stay tuned for more!