CVE-2026-40887
JavaScript vulnerability analysis and mitigation

Overview

CVE-2026-40887 is an unauthenticated SQL injection vulnerability in the Vendure open-source headless commerce platform's Shop API. A user-controlled languageCode query string parameter is interpolated directly into a raw SQL expression without parameterization or runtime validation, allowing arbitrary SQL execution against the database. Affected versions span @vendure/core >=1.7.4 and <2.3.4, >=3.0.0 and <3.5.7, and >=3.6.0 and <3.6.2, covering all supported database backends (PostgreSQL, MySQL/MariaDB, SQLite). The vulnerability was published on April 21, 2026, with a CVSS v3.1 base score of 9.1 (Critical) (GitHub Advisory, Feedly).

Technical details

The root cause (CWE-89) lies in ProductService.findOneBySlug, where the request context's languageCode value is embedded directly into a SQL CASE expression via a JavaScript template literal, bypassing TypeORM's parameterization entirely:

.addSelect(
  `CASE translation.languageCode WHEN '${ctx.languageCode}' THEN 2 WHEN '${ctx.channel.defaultLanguageCode}' THEN 1 ELSE 0 END`,
  'sort_order',
)

Although languageCode is cast to a TypeScript LanguageCode type at compile time, no runtime validation is performed — the raw HTTP query string value is used as-is. An unauthenticated attacker can append a crafted languageCode query parameter to any Shop API request to inject arbitrary SQL. The Admin API is also vulnerable but requires authentication for exploitation (GitHub Advisory).

Impact

Successful exploitation allows an unauthenticated attacker to execute arbitrary SQL against the underlying database, resulting in high confidentiality impact (unauthorized access to sensitive data such as customer PII, order history, and credentials) and high availability impact (potential to disrupt or destroy database contents). All supported database backends are affected, meaning the scope of exposure extends to any Vendure deployment regardless of database choice. While integrity impact is rated None in the CVSS score, practical SQL injection exploitation can enable data modification depending on database permissions and configuration (GitHub Advisory, Feedly).

Exploitability

No public proof-of-concept exploit code has been confirmed, and there is no evidence of in-the-wild exploitation at the time of disclosure (Feedly). However, the vulnerability is trivially exploitable — it requires no authentication, no user interaction, and is reachable on every default Vendure installation via a simple query string manipulation. The EPSS score is 0.054 (5.4%), and the CVE does not currently appear in the CISA KEV catalog. Notably, ProjectDiscovery has added multiple Nuclei detection templates for this CVE, indicating active tooling development by the security community (Nuclei Templates).

Exploitation steps

  1. Reconnaissance: Identify internet-facing Vendure instances using search engines (Shodan, Censys) or by detecting Vendure-specific API endpoints (e.g., /shop-api). Confirm the version is within the affected range (>=1.7.4, <2.3.4 or >=3.0.0, <3.5.7 or >=3.6.0, <3.6.2).
  2. Identify the vulnerable parameter: The languageCode query string parameter is accepted on any Shop API request (e.g., GET /shop-api?languageCode=en).
  3. Craft the SQL injection payload: Append a malicious languageCode value that breaks out of the SQL CASE expression and injects arbitrary SQL. For example:
    GET /shop-api?languageCode=en' UNION SELECT username,password,NULL FROM admin_user--
  4. Execute and extract data: Send the crafted request to the Shop API. The injected SQL is interpolated directly into the query and executed by the database engine, returning sensitive data in the API response or via error messages.
  5. Escalate (optional): Use blind SQL injection techniques (time-based or boolean-based) if direct output is not reflected, or leverage database-specific features (e.g., xp_cmdshell on MSSQL, LOAD_FILE/INTO OUTFILE on MySQL) for further system access depending on database permissions (GitHub Advisory).

Indicators of compromise

  • Network: Unusual HTTP requests to the Vendure Shop API (/shop-api) containing SQL metacharacters or keywords (e.g., ', UNION, SELECT, --, OR 1=1) in the languageCode query parameter; unexpected outbound database connections from the application server.
  • Logs: Web server or application access logs showing requests with anomalous languageCode values (e.g., values containing quotes, SQL keywords, or encoded characters); database error logs indicating SQL syntax errors or unexpected query structures.
  • Application Behavior: Unexpected API responses containing database schema information, user credentials, or data from unrelated tables; increased query execution times suggesting time-based blind SQL injection attempts.
  • File System: Unexpected files written to the web root or application directory if the database user has file write privileges (e.g., MySQL INTO OUTFILE abuse) (GitHub Advisory).

Mitigation and workarounds

Immediate action: Upgrade @vendure/core to a patched version — 2.3.4 (for 2.x users), 3.5.7 (for 3.5.x users), or 3.6.2 (for 3.6.x users). Patched versions convert the vulnerable SQL interpolation to a parameterized query as defense in depth. If an immediate upgrade is not possible, apply the following hotfix to RequestContextService.getLanguageCode in packages/core/src/service/helpers/request-context/request-context.service.ts:

private getLanguageCode(req: Request, channel: Channel): LanguageCode | undefined {
  const queryLanguageCode = req.query?.languageCode as string | undefined;
  const isValidFormat = queryLanguageCode && /^[a-zA-Z0-9_-]+$/.test(queryLanguageCode);
  return (
    (isValidFormat ? (queryLanguageCode as LanguageCode) : undefined) ??
    channel.defaultLanguageCode ??
    this.configService.defaultLanguageCode
  );
}

This validates the languageCode input at the request boundary, silently dropping invalid values and falling back to the channel's default language. Additionally, consider implementing network-level controls to restrict Shop API access from untrusted networks where feasible (GitHub Advisory).

Community reactions

The vulnerability was reported by security researcher jacobfrantz1 and published by Vendure maintainer michaelbromley via a GitHub Security Advisory on April 13, 2026 (GitHub Advisory). ProjectDiscovery's Nuclei Templates repository saw multiple commits adding detection templates for CVE-2026-40887 in the days following disclosure, reflecting active community interest in automated detection (Nuclei Templates). A Bluesky post from beikokucyber.bsky.social and coverage on security aggregators such as infinitsec.net and radar.offseq.com indicate moderate community awareness of the vulnerability.

Additional resources


SourceThis report was generated using AI

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

CVE-2026-63376HIGH8.2
  • JavaScript logoJavaScript
  • cockpit-image-builder.src
NoYesSep 03, 2026
GHSA-7q9c-hpx7-9cwmHIGH7.5
  • JavaScript logoJavaScript
  • @typespec/spector
NoYesSep 04, 2026
CVE-2026-77465HIGH7.5
  • JavaScript logoJavaScript
  • toml
NoYesSep 03, 2026
CVE-2026-71429MEDIUM6.2
  • JavaScript logoJavaScript
  • stream-json
NoYesSep 03, 2026
GHSA-6hxq-p678-4hr2LOW2
  • JavaScript logoJavaScript
  • @simplewebauthn/server
NoYesSep 04, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management