# Validation bypass for queries generated for PostgreSQL

Rails' PostgreSQL sanitize_sql_array truncates bound strings at a null byte, so `test\0dummy` matches `test`, bypassing Ruby-side blacklist/suffix validation.

- Payout: $1,500
- Severity: medium
- Program: Ruby on Rails
- Credited: ooooooo_q
- Disclosed: 2018-11-19
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/394253
- Library page: https://bugbountylibrary.com/r/h1%3A394253
- Tags: domain:web impact:integrity kind:bounty platform:hackerone sev:medium tech:ruby technique:parser-differential vuln:auth-bypass vuln:sqli

**Target:** ActiveRecord PostgreSQL adapter / sanitize_sql_array
**Root cause:** PostgreSQL adapter's quote/sanitize path truncates the string at the first null byte instead of raising, unlike MySQL (escapes) and SQLite (preserves), so the generated SQL literal silently drops everything after \0.
**Steps:**
1. Create Rails 5.2.1 app with `--database=postgresql`, generate Article model, migrate, insert title 'test title'
2. Run `Article.where("title = ?", "test title\0suffix")` — generated SQL is `WHERE (title = 'test title')`, suffix dropped
3. Compare `ActiveRecord::Base.send(:sanitize_sql_array,['... title = ?', "abc\0suffix"])` on PG (truncates) vs MySQL (escapes `\0`) vs SQLite (preserves)
4. Observe hash-condition and find_by forms raise ArgumentError, but raw `?`/`:title` placeholder forms silently truncate
**How found:** Researcher noticed inconsistent behavior: hash-style conditions raised 'string contains null byte' while `?`/named placeholders silently succeeded, then diffed sanitize_sql_array output across PostgreSQL, MySQL, and SQLite to isolate the PG-specific truncation.
**Exploitation:** Application performs a Ruby-side blacklist/equality check on the raw string (e.g. `title != 'test'`) then passes it to a `?` placeholder query; attacker supplies `test\0dummy` which passes the Ruby check but the DB sees only `test`, matching the forbidden value.
**Insight:** When a framework has multiple query-building paths, test the same malicious input against each — one path may raise while another silently mangles input. Diff sanitizer output across DB adapters; null-byte truncation in one adapter turns Ruby-side validation into a bypass.
