# SQL injection in MilestoneFinder order method

Unsantized `order` param passed to ActiveRecord `reorder` in MilestoneFinder enabled boolean-based blind SQLi, letting any user dump the GitLab database including tokens.

- Payout: $2,000
- Severity: critical
- Program: GitLab
- Credited: jobert
- Disclosed: 2018-04-27
- CVE: CVE-2017-0914
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/298176
- Library page: https://bugbountylibrary.com/r/h1%3A298176
- Tags: domain:web impact:ato impact:data-leak impact:privesc kind:bounty platform:hackerone sev:critical tech:ruby technique:blind technique:source-review vuln:access-control vuln:sqli

**Target:** Groups::MilestonesController index / MilestoneFinder order
**Root cause:** `params[:order]` is passed directly to `items.reorder()` without allowlisting or sanitization, so attacker-controlled SQL is injected into the ORDER BY clause.
**Steps:**
1. Create a group and two milestones; note their IDs.
2. Send `GET /groups/<group>/-/milestones?state=open&order=<payload>` with Accept: application/json.
3. Use payload `(CASE SUBSTR((SELECT email FROM users WHERE username='jobertabma'),1,1) WHEN 'a' THEN (CASE id WHEN 429944 THEN 2 ELSE 1 END) ELSE 1 END)` URL-encoded.
4. Observe response ordering: reversed order confirms the guessed character.
5. Iterate characters and SUBSTR index to exfiltrate arbitrary column values.
**How found:** Code review of MilestoneFinder#order showed `reorder(params[:order])` with no sanitization; recognized ORDER BY as an injectable sink and built a CASE-based boolean oracle using milestone IDs to make the sort order observable.
**Exploitation:** Blind boolean SQLi via ORDER BY: attacker crafts a CASE expression that sorts on column 2 only when the guessed character matches, then reads the JSON response order to determine the character. Enumerate all chars of any column (e.g. users.email, private tokens) to dump the DB.
**Escalation:** Extracted private access and shell tokens can be used to elevate privileges, potentially leading to arbitrary code execution.
**Insight:** ORDER BY / reorder is a frequently overlooked SQLi sink because it can't take placeholders; use CASE expressions keyed on a known row ID to turn sort order into a boolean oracle when the query result is returned to the user.
