Skip to content

Commit 07f4ff5

Browse files
notSumit25claude
andcommitted
docs(security): correct HTTP exploit path for the identifier-injection finding
Hands-on QA against the live stack found the ;-based DROP TABLE payload is blocked by StrictHttpFirewall before the controller runs, so multi-statement chaining is not reachable through the HTTP endpoint. The quote breakout is: orders" AS x returned 200 unpatched (executed as an aliased table) and 400 patched. The quoter flaw and the fix are unchanged; only the exploit framing is corrected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent aceb7cd commit 07f4ff5

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

‎docs/security/2026-09-16-sql-injection-quote-identifier.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ No errors at all — the count returned, the table was dropped, the trailing sel
6161
rows. The payload contains no `/`, so Spring's `StrictHttpFirewall` (which rejects `%2F`) does
6262
not stand in its way.
6363

64+
**HTTP exploit path — corrected by hands-on QA.** The reproduction above uses `psql` and a
65+
`;`-separated `DROP TABLE`, which demonstrates the *quoter* flaw exactly. But over the real HTTP
66+
endpoint, Spring's `StrictHttpFirewall` rejects a `;` in a path segment (400) before the
67+
controller runs, so multi-statement chaining is **not** reachable that way. The double quote
68+
*is* allowed through, so the HTTP-reachable exploit is a **single-statement quote breakout**:
69+
`tableName` = `orders" AS x` returned **200** on the unpatched backend (the quote closed the
70+
identifier and `"orders" AS x` executed as an aliased table reference) and **400** on the fixed
71+
one. `nonexistent_xyz" AS x` also returned 200 unpatched, so the attacker controls the whole
72+
FROM clause regardless of any real table name. The fix blocks both the quote breakout and,
73+
defensively, the semicolon form.
74+
6475
**There is no second line of defence on this path.** It never reaches
6576
`QueryExecutorService`, so it gets no `connection.setReadOnly(true)`, no policy service and no
6677
row cap — a `grep` for `setReadOnly` over `src/main/java` returns exactly one hit, and it is

0 commit comments

Comments
 (0)