Skip to content

harden quote_literal against standard_conforming_st… - #107

Merged
isdaniel merged 2 commits into
mainfrom
security/sql-literal-escaping
Jul 23, 2026
Merged

harden quote_literal against standard_conforming_st…#107
isdaniel merged 2 commits into
mainfrom
security/sql-literal-escaping

Conversation

@isdaniel

@isdaniel isdaniel commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Problem

quote_literal doubled single quotes but ignored backslashes. That is only safe when the server has standard_conforming_strings = on. With it off (deprecated, but still settable per session on a normal connection), a backslash lets a crafted value terminate the string literal early:

 input:   \'; DROP TABLE t; --
 before:  '\''; DROP TABLE t; --'   ← \' becomes a literal quote → string closes → injection

Fix

Consolidate quote_ident and quote_literal onto one private quote_internal(value, QuoteStyle) — a faithful port of libpq's PQescapeInternal (the algorithm rust-postgres's escape_literal also ports). A literal containing a backslash now switches to the escape-string form E'…' with backslashes doubled, correct under either standard_conforming_strings setting:

…rings=off

Consolidate quote_ident/quote_literal onto a shared quote_internal core that
mirrors libpq PQescapeInternal: literals containing a backslash now use the
escape-string form ( E'...') with backslashes doubled, so the result is safe
regardless of the server's standard_conforming_strings setting. Backslash-free
literals and all identifiers are byte-for-byte unchanged; null-byte rejection
is preserved.

Also update the two backend test-only assertions that pinned the pre-hardening
quote_literal output for a backslash input.

ci: run quote_literal_scs_off in the integration job

Wire the new standard_conforming_strings=off roundtrip test into the CI
integration run block (regular connection via DATABASE_URL_REGULAR; creates
no replication slot, so no slot-cleanup step follows it).
@codspeed-hq

codspeed-hq Bot commented Jul 22, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 50 untouched benchmarks


Comparing security/sql-literal-escaping (1edc543) with main (547b721)

Open in CodSpeed

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.73%. Comparing base (547b721) to head (1edc543).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #107      +/-   ##
==========================================
- Coverage   94.75%   94.73%   -0.02%     
==========================================
  Files          27       27              
  Lines       20623    20678      +55     
==========================================
+ Hits        19541    19590      +49     
- Misses       1082     1088       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens quote_literal to be injection-safe even when PostgreSQL session setting standard_conforming_strings = off by switching to escape-string literals and doubling backslashes when needed, aligning behavior with libpq-style escaping.

Changes:

  • Introduces a shared quote_internal(value, QuoteStyle) implementation used by both quote_ident and quote_literal.
  • Updates unit tests to assert the new quote_literal behavior for backslash-containing inputs and adds coverage through a real SQL builder.
  • Adds a live PostgreSQL integration test (quote_literal_scs_off) and wires it into CI integration runs.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/sql_builder.rs Refactors quoting into quote_internal and changes quote_literal behavior for backslashes (escape-string form).
src/connection/native/connection.rs Updates tests to reflect the new quoting behavior for backslash+quote inputs.
src/connection/libpq.rs Updates tests to reflect the new quoting behavior for backslash+quote inputs.
integration-tests/quote_literal_scs_off.rs Adds an ignored live-DB test validating safety/roundtrip under standard_conforming_strings off/on.
Cargo.toml Registers the new integration test target.
.github/workflows/ci-checks.yml Runs the new ignored integration test in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/sql_builder.rs
Comment thread integration-tests/quote_literal_scs_off.rs
@isdaniel

Copy link
Copy Markdown
Owner Author

@codex[agent] review

@Codex

Codex AI commented Jul 23, 2026

Copy link
Copy Markdown

@codex[agent] review

Reviewed the PR, checked CI status/logs, and validated locally with cargo fmt --all -- --check plus cargo test --lib --features derive. I didn’t find any additional changes needed.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 192.0.2.1
    • Triggering command: /home/REDACTED/work/pg-walstream/pg-walstream/target/debug/deps/pg_walstream-28c626f7cc1cc04e /home/REDACTED/work/pg-walstream/pg-walstream/target/debug/deps/pg_walstream-28c626f7cc1cc04e f/aws-lc-sys-0.4-a linux-musl/path//home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3getconf f/aws-lc-sys-0.4/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3LONG_BIT de ws-lc-sys-1734e3142e916484/out/libaws_lc_0_43_0_crypto.a ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_obj.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_req.o ws-lc-sys-1734e3lsb_release ws-lc-sys-1734e3-a ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_txt.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_v3.o ws-l�� ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_vpm.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_algor.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_all.o ws-lc-sys-1734e3getconf ws-lc-sys-1734e3LONG_BIT ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_exten.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_name.o (packet block)
  • invalid_host_that_does_not_exist
    • Triggering command: /home/REDACTED/work/pg-walstream/pg-walstream/target/debug/deps/pg_walstream-28c626f7cc1cc04e /home/REDACTED/work/pg-walstream/pg-walstream/target/debug/deps/pg_walstream-28c626f7cc1cc04e f/aws-lc-sys-0.4-a linux-musl/path//home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3getconf f/aws-lc-sys-0.4/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3/home/REDACTED/work/pg-walstream/pg-walstream/target/debug/build/aws-lc-sys-1734e3LONG_BIT de ws-lc-sys-1734e3142e916484/out/libaws_lc_0_43_0_crypto.a ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_obj.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_req.o ws-lc-sys-1734e3lsb_release ws-lc-sys-1734e3-a ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_txt.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_v3.o ws-l�� ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x509_vpm.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_algor.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_all.o ws-lc-sys-1734e3getconf ws-lc-sys-1734e3LONG_BIT ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_exten.o ws-lc-sys-1734e3142e916484/out/ebcd52e9457b6221-x_name.o (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@isdaniel

Copy link
Copy Markdown
Owner Author

@copilot review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/sql_builder.rs
Comment thread src/connection/libpq.rs

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown

@copilot review

Review found and fixed three regressions locally: replication commands now use their own SCONST quoting, libpq sets UTF-8 in startup parameters so physical replication connections remain valid, and the live test exercises adjacent \' plus ordinary backslashes. Commits 2821ed0 and eb4ac07; tests and CodeQL pass. GitHub currently rejects pushing them because the head branch is protected.

@isdaniel
isdaniel merged commit cca0144 into main Jul 23, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants