August 6, 2026
How a Single Unauthenticated GraphQL Request Compromised Mozilla Firefox CI — $12,000 Bounty
Overview

By Kenjisubagja
1 min read
Overview
A critical Remote Code Execution (RCE) vulnerability was discovered in Mozilla's Taskcluster web-server — the core infrastructure responsible for building and testing Firefox CI.
Without needing any authentication, tokens, or special HTTP headers, an attacker could execute arbitrary JavaScript directly inside the Node.js process by sending a single HTTP POST request to the public /graphql endpoint.
How It Happened
The vulnerability is the result of a root cause chain involving permissive inputs, unsanitized parameters, and dynamic code evaluation in a third-party dependency:
- Free-Form JSON Input: The public
/graphqlendpoint accepted an open, arbitraryJSONscalar object as a queryfilterargument. - Unsanitized Filtering with
sift: The server forwarded this raw JSON input directly into thesiftlibrary (a MongoDB-like query builder for JavaScript) without stripping or validating operators. - Code Evaluation via
$where: Insiftversion 17.1.3, passing a$wherecondition compiles the provided string into an executable JavaScript function usingnew Function(). - Anonymous Execution Path: The GraphQL endpoint allowed anonymous callers. Because the
anonymousrole held sufficient default scopes, the query resolver executed normally, passing the filter intosiftand immediately triggering the malicious JavaScript.
Impact
Since the code runs directly within the host's Node.js process, an attacker could execute arbitrary shell commands and extract all environment variables, leading to a total cluster compromise:
- Database Credentials: Full PostgreSQL credentials (
READ_DB_URLandWRITE_DB_URL). - Deployment Access Tokens: Exfiltration of
TASKCLUSTER_ACCESS_TOKEN, granting control over the entire Taskcluster deployment. - OAuth Client Secrets: Client secrets for Auth0 and GitHub integrations.
- Database Encryption & Session Keys: Column encryption keys and
SESSION_SECRET(which was set to a default value,FIXME).
Key Takeaways & Remediation
This incident highlights critical security best practices when working with dynamic query engines:
- Sanitize Dynamic Queries: Never pass raw, free-form JSON objects directly to query engines like
siftwithout stripping operator keys starting with $. - Use Strict Input Schemas: Avoid using generic
JSONscalar types in GraphQL endpoints; define explicit input types with allowlisted fields instead. - Disable Dynamic Code Evaluation: Ensure third-party dependencies do not evaluate untrusted input via
eval()ornew Function(). - Credential Hygiene: Ensure production environments never use placeholder or default secret values (e.g.,
SESSION_SECRET=FIXME).
This write-up is an educational summary based on public transparency reports. For the full report and communication timeline, visit the Original HackerOne Report #3782701.