# SQL injection via concatenated queries

User values joined into SQL text instead of bound; check ORDER BY sinks, SECURITY DEFINER helpers, legacy endpoints

_Area: Web injection and code execution. Seen in 16 disclosed reports; 8 confirmed bounties, median $3,000, range $165-$10,000; latest 2026-08-05. Updated 2026-10-23._

## How it works

A query string is assembled by joining user-controlled values into SQL text, so the database parses those values as code rather than data. The broken assumption is that a validator, filter, or "internal" caller makes input safe. Any quote, keyword, or object shape that survives the filter changes the query's structure. The fix that holds is binding: values travel as parameters and the SQL text is fixed before input arrives.

## Where it shows up

- String concatenation or interpolation into SQL, including `format()`/`EXECUTE`/`dblink_exec` sinks inside `SECURITY DEFINER` functions.
- ORDER BY / `reorder()` sinks, which cannot take placeholders and are often passed raw [E2](https://bugbountylibrary.com/r/h1%3A298176.md).
- Unauthenticated AJAX actions and preview handlers that render shortcodes whose attributes map to SQL clauses [E1](https://bugbountylibrary.com/r/h1%3A273946.md).
- Legacy endpoints (old ISAPI DLLs, `.asmx` SOAP methods) that bypass newer input handling on the same product.
- SQL functions that execute code by default (`GROOVY()`), turning any injection into RCE [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md).
- Homegrown filters that split on commas or strip patterns, leaving equivalent syntax (CASE, LIKE, casts) usable [E4](https://bugbountylibrary.com/r/blog%3Ablog-redforce-io-sql-injection-in-insert-update-query-without-comma.md).
- Logging paths that interpolate a header (User-Agent) into an INSERT after only tag-stripping [E5](https://bugbountylibrary.com/r/blog%3Arenaudmarti-net-posts-first-bug-bounty-submission.md).
- Email fields concatenated into raw SQL; RFC 5322 permits quotes that validators like `filter_var` accept [E7](https://bugbountylibrary.com/r/blog%3Asec-stealthcopter-com-ninja-contact-forms.md).
- Invite-code lookups in signup flows validated by raw SQL [E8](https://bugbountylibrary.com/r/h1%3A2209130.md).

## How to review

Grep for string-built SQL (concatenation, `format`, `EXECUTE`, `dblink`, `reorder`), then trace each sink's arguments back to user-reachable input. The invariant: the query text is fully determined before any user value is supplied. Test it by confirming the sink uses bound parameters, not by checking that a filter exists. Checklist: `SECURITY DEFINER` helpers bind their arguments; legacy endpoints share the modern data-access layer; ORDER BY values are allowlisted, not interpolated. For each injection point, ask what the DB account can do: superuser, stacked statements, Java authoring, code-exec functions [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md)[E6](https://bugbountylibrary.com/r/blog%3Ahuntress-com-blog-khunt-malware-sql-injection-oracle.md).

## Variants seen

- Unauthenticated shortcode-attribute injection in a WordPress plugin preview action [E1](https://bugbountylibrary.com/r/h1%3A273946.md).
- ORDER BY injection via `reorder(params[:order])` in a Rails finder [E2](https://bugbountylibrary.com/r/h1%3A298176.md).
- Injection escalated by a default-on code-execution SQL function [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md).
- Filter bypass using alternative syntax when commas are blocked [E4](https://bugbountylibrary.com/r/blog%3Ablog-redforce-io-sql-injection-in-insert-update-query-without-comma.md).
- Header value interpolated into INSERT after tag-strip-only filtering, chained to stored XSS [E5](https://bugbountylibrary.com/r/blog%3Arenaudmarti-net-posts-first-bug-bounty-submission.md).
- Injection escalated by privilege-gated Java source authoring in Oracle [E6](https://bugbountylibrary.com/r/blog%3Ahuntress-com-blog-khunt-malware-sql-injection-oracle.md).
- Quote-bearing email concatenated into a GDPR export query [E7](https://bugbountylibrary.com/r/blog%3Asec-stealthcopter-com-ninja-contact-forms.md).
- Time-based blind injection in an invite-code signup lookup [E8](https://bugbountylibrary.com/r/h1%3A2209130.md).

## Why fixes fail

Pattern-based sanitizers (comma splitting, regex stripping of `OPTION(...)`) were bypassed with equivalent SQL syntax [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md)[E4](https://bugbountylibrary.com/r/blog%3Ablog-redforce-io-sql-injection-in-insert-update-query-without-comma.md); fixing one endpoint left legacy paths exposed.

## Impact and severity

Ranged from PII and password disclosure [E2](https://bugbountylibrary.com/r/h1%3A298176.md)[E7](https://bugbountylibrary.com/r/blog%3Asec-stealthcopter-com-ninja-contact-forms.md) to unauthenticated RCE and file writes, superuser access and supply-chain reach, and cluster-wide root compromise with cloud credential theft [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md)[E6](https://bugbountylibrary.com/r/blog%3Ahuntress-com-blog-khunt-malware-sql-injection-oracle.md). Severity rose with unauthenticated reachability, high-privilege DB accounts, and code-execution features enabled by default.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A273946.md
- E2: https://bugbountylibrary.com/r/h1%3A298176.md
- E3: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-06-09-apache-pinot-sqli-rce-html.md
- E4: https://bugbountylibrary.com/r/blog%3Ablog-redforce-io-sql-injection-in-insert-update-query-without-comma.md
- E5: https://bugbountylibrary.com/r/blog%3Arenaudmarti-net-posts-first-bug-bounty-submission.md
- E6: https://bugbountylibrary.com/r/blog%3Ahuntress-com-blog-khunt-malware-sql-injection-oracle.md
- E7: https://bugbountylibrary.com/r/blog%3Asec-stealthcopter-com-ninja-contact-forms.md
- E8: https://bugbountylibrary.com/r/h1%3A2209130.md
