Oct 3, 2026·6 min read·5 visits
Authenticated cross-tenant SQL injection in Trigger.dev via unsanitized window-function names in the TSQL compiler allows unauthorized extraction of other organizations' data.
A critical cross-tenant SQL injection vulnerability exists in the TSQL query compiler of Trigger.dev, allowing authenticated users to bypass tenant isolation boundaries and read arbitrary ClickHouse analytics logs and execution payloads belonging to other organizations.
The Trigger.dev platform implements a custom query language interface (TSQL/TRQL) exposed at the POST /api/v1/query endpoint to allow developers to query task execution analytics and run logs. This query language undergoes compilation into raw ClickHouse SQL through an internal parsing and printing package (internal-packages/tsql).
While the compiler applies sanitization, parameter binding, and mandatory tenant-scoping filters to standard queries, it fails to sanitize or validate window function names. This omission exposes an attack surface where any authenticated user can bypass tenant boundaries and exfiltrate database records belonging to other tenants.
This vulnerability is classified under CWE-89 (Improper Neutralization of Special Elements used in an SQL Command) and CWE-639 (Authorization Bypass Through User-Controlled Key). The flaw permits direct read-access to the underlying ClickHouse database containing sensitive customer payloads, environment variables, and execution parameters.
The root cause of the vulnerability lies in the implementation of the visitWindowFunction AST node printer within internal-packages/tsql/src/query/printer.ts. When formatting window functions for the final ClickHouse query, the printer directly concatenates the node.name property into the raw SQL string without any escaping or validation checks.
While typical SQL functions are restricted to an allowlist of valid names, the TSQL compiler does not enforce such constraints for window functions. Furthermore, the TSQL lexer permits backtick-quoted identifiers, which are intended to let developers use special characters in column names. When processing backticks, the lexer strips the quotes and unescapes the inner string, passing the raw string as the function name to the AST.
By enclosing a malicious SQL fragment containing a subquery within backticks in the window function position, an attacker can break out of the analytical query context. The automatically generated tenant isolation guard (enforcedWhereClause) is only applied to the WHERE clause of the outer table. The injected subquery executes within the SELECT context as an independent expression, entirely unaffected by the outer query's isolation limits.
The vulnerable code path handles the WindowFunction AST node by generating an unvalidated string representation of the function call. Below is the code implementation prior to the fix:
// Vulnerable implementation in internal-packages/tsql/src/query/printer.ts
private visitWindowFunction(node: WindowFunction): string {
const args = node.args ? node.args.map((a) => this.visit(a)) : [];
// node.name is concatenated directly into the query string without sanitization
const funcCall = `${node.name}(${args.join(", ")})`;
if (node.over_identifier) {
return `${funcCall} OVER ${this.printIdentifier(node.over_identifier)}`;
}
// ...
}In the patched version, the maintainers introduced strict allowlist validation using findTSQLFunction and findTSQLAggregation. This validation maps the input function name against a registry of safe analytical functions and retrieves the corresponding safe ClickHouse name:
// Patched implementation in internal-packages/tsql/src/query/printer.ts
private visitWindowFunction(node: WindowFunction): string {
// Validate the function name against the allowlist and resolve it to its safe ClickHouse name
const funcMeta = findTSQLFunction(node.name) ?? findTSQLAggregation(node.name);
if (!funcMeta) {
throw new QueryError(`Unknown function: ${node.name}`);
}
const args = node.args ? node.args.map((a) => this.visit(a)) : [];
const funcCall = `${funcMeta.clickhouseName}(${args.join(", ")})`;
if (node.over_identifier) {
return `${funcCall} OVER ${this.printIdentifier(node.over_identifier)}`;
}
// ...
}This remediation completely closes the vulnerability by rejecting any unauthorized or malformed window function name prior to database execution.
An exploitation flow requires the attacker to possess valid standard API credentials or a JWT to authenticate to the POST /api/v1/query endpoint. This prerequisite is low-complexity since any legitimate tenant on a self-hosted or cloud-hosted instance of Trigger.dev can perform the request.
The attacker constructs a TSQL payload targeting their own task_runs table, which satisfies the initial authorization checks. Inside the projection list of the SELECT statement, the attacker introduces a window function definition with a name enclosed in backticks. The backtick string encapsulates the malicious subquery payload.
During processing, the compiler compiles this node into a raw ClickHouse subquery. Because ClickHouse executes subqueries in the SELECT list independently, the database retrieves records from other tables (e.g., trigger_dev.task_runs_v2) for any specified organization_id. The resulting dataset containing the exfiltrated sensitive data is mapped to an alias and returned in the HTTP response.
Here is a sequence diagram of the exploitation process:
The security impact of this vulnerability is significant, as it completely breaks the multi-tenant isolation model of Trigger.dev. An attacker can run arbitrary read-only queries against the analytical database, compromising the confidentiality of all tenant data stored within the ClickHouse instance.
This data includes historical task runs, execution payloads, logs, internal environment variables, API secret keys, and customer database passwords processed during job executions. In worst-case scenarios, the exposed payloads can leak highly sensitive credentials, leading to secondary compromises of connected systems.
Since this is an SQL injection targeting ClickHouse, write operations or local file system access are generally restricted by the database engine permissions. However, the complete disclosure of execution records makes this a high-severity incident with CVSS score 7.7 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N).
To remediate this vulnerability, self-hosted and cloud operators must immediately upgrade their deployments to version 4.5.6 or later. This release incorporates the official validation patch that terminates compilation if an unrecognized window function name is supplied.
In environments where upgrading is delayed, Web Application Firewalls (WAFs) can be deployed to inspect traffic hitting the POST /api/v1/query endpoint. Security teams should implement rules to search the query payload for backticks combined with typical SQL keywords such as SELECT, FROM, or WHERE within the identifier block.
Additionally, database logs for ClickHouse should be continuously audited for queries executing against the task_runs_v2 table that contain mismatching organization_id fields or multiple nested SELECT queries containing the string OVER with non-standard functions.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
trigger.dev Trigger.dev | <= 4.5.5 | 4.5.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-89, CWE-639 |
| Attack Vector | Network |
| CVSS Score | 7.7 (High) |
| Exploit Status | Proof of Concept (PoC) available |
| KEV Status | Not Listed |
| Impact | Cross-tenant data exfiltration |
The software constructs an SQL command using unsanitized input that allows an attacker to alter the query structure.
A logical authorization bypass vulnerability exists in Trigger.dev versions prior to 4.5.6. This flaw allows an authenticated client with a low-trust environment API key, such as development or staging, to cancel active worker deployments in a higher-trust environment like production within the same project. The vulnerability occurs because write operations on deployments were scoped solely by project identifier instead of environment identifier.
An in-depth technical analysis of multiple critical security flaws identified in the Vibe-Trading ecosystem (vibe-trading-ai). These issues range from unauthenticated remote command injection via agent tool executions to arbitrary Python execution through dynamic module loading and unsafe Jinja2 template autoescaping, allowing full system compromise.
An arbitrary file read and path traversal vulnerability in the Vibe-Trading platform allows unauthenticated remote attackers to retrieve sensitive configuration files, API keys, and system secrets. The flaw stems from permissive directory checking in path validation tools and a complete lack of input sanitization in the document reader utility. Remediation was introduced in version 0.1.7 by implementing strict path allowlists, forcing user authentication, and dropping root execution privileges within the container environment.
The vibe-trading-ai package prior to version 0.1.7 contains multiple critical security vulnerabilities including unauthenticated remote code execution (RCE) via session message injection, missing authentication on read endpoints, unrestricted file upload, insecure CORS policies, and sensitive key disclosure. Because the application default settings failed open, ran as root within Docker, and bound to all interfaces, remote unauthenticated attackers could compromise host environments containing sensitive trading data.
CVE-2026-18140 is a denial-of-service vulnerability in the Amazon aws-smithy-json Rust crate. Under-validation of recursion depth within the unknown-key skipping path allows a remote, unauthenticated attacker to cause stack exhaustion and process aborts by sending deeply nested JSON arrays.
A sensitive information disclosure vulnerability exists in the Trigger.dev Command Line Interface (CLI) framework. When executing build processes inside CLI v3 packages, the framework's debug deployment logs print unredacted, resolved environment variables and secrets to standard output or log streams. This exposure occurs when the CLI is operated with a high logging verbosity level, enabling any individual or automated system with read access to build logs, CI/CD output consoles, or local development streams to capture plaintext sensitive parameters, such as database credentials, API keys, and private external integration tokens.