Security Advisories (1)
CVE-2026-121265 (2026-11-07)

SQL::Abstract versions before 2.000003 for Perl allow SQL injection via an arrayref column value in insert and update. With the array_datatypes option off, which is the default, insert(), update() and values() treat an arrayref column value as literal SQL. Its first element goes into the SQL text unescaped and the rest become bind values. A JSON array, or a repeated form field decoded as an arrayref, is such a value. An application that passes request data as column values to insert or update with the default options allows SQL injection. Releases before 2.000003 also treat an arrayref in generate() as literal SQL, including through AUTOLOAD when allow_autoload is on, whatever array_datatypes is set to.

Changes for version 2.000001_01 - 2026-09-27

  • SQL::Abstract::Parts: drop the leftover `use Module::Runtime`. It was never called, and Module::Runtime stopped being a prerequisite in 2.000001, so on a system without it installed loading Parts.pm (and hence the whole render path that builds Parts objects) died at compile time
  • SQL::Abstract::Tree: pad_keyword() no longer emits "Use of uninitialized value" warnings when a caller supplies an indentmap without a newline (it now guards newline the way _unparse already does)
  • SQL::Abstract::Tree: a (NOT) BETWEEN now parses both of its bounds into a single AND grouped under the BETWEEN node (BETWEEN[val, AND[low, high]]) instead of letting the upper bound leak out as a sibling in the enclosing expression. The re-parse that was meant to do this never fired, because it compared an arrayref node against the string '-LITERAL'. Emitted SQL text round-trips unchanged; only the parsed tree (parse()) is affected.
  • select() now dies when given more than the four positional arguments (source, fields, where, order) instead of rendering garbage SQL from a flat clause list that was meant to be a hashref (RT#148271, Ovid)
  • ExtraClauses: -join accepts the dashed spellings -as / -on / -using / -type / -to / -from like the surrounding from_list does, and dies on an unknown key instead of silently dropping it (RT#148271, Ovid)
  • SQL::Abstract::Tree: recognise Oracle's MINUS as an expression start keyword, like EXCEPT (RT#134245, DAMI)
  • SQL::Abstract::Tree: anchor the unrollable-operator regex so that ON no longer matches inside function names such as GROUP_CONCAT or CONCAT_WS and strips their parenthesis on unparse/format (RT#105563, RT#117234)
  • An undef element in a -row (and so in -values and the ExtraClauses insert rowvalues clause) is now a NULL bind instead of being silently dropped, which lost placeholders and bind values in bulk inserts (RT#137357)
  • Add regression coverage confirming an empty arrayref given to -and / -or in a where clause emits no SQL and no trailing AND/OR (correct since the v2 engine; locks it against regressions) (RT#126990, GH#15, fabzzap)
  • Document that the bundled DBIx::Class::* helper modules require DBIx::Class at runtime (intentionally not a prereq, to avoid a dependency cycle)
  • Document the limits of the default injection_guard and the safe handling of untrusted input (bind values, quote_char) (RT#117059)
  • generate() in scalar context now interpolates each placeholder exactly once, so a bind value that contains a '?' no longer swallows the following bind values
  • Reword the "removed in 2.0" deprecation warnings to "a future version", since those code paths still ship in the 2.x line
  • Do not warn when a plain hashref is passed as a bind value to insert() - this is how Postgres json/jsonb columns are supplied (GH#18, RT#120676, kraih)
  • Speed up the top-level special-op check with a single precompiled regex instead of a List::Util::first scan (GH#21, larryl)
  • Fix ExtraClauses POD NAME/synopsis to the real package name and the documented plugin('+ExtraClauses') usage
  • Correct the 'pending%' bind value in the -like POD example (GH#24, lucas1)
  • SQL::Abstract::Tree: preserve a real 0 / '0' bind value in fill_in_placeholder() instead of blanking it (was `|| ''`) (RT#125760)
  • Add DBIx::Class::SQLMaker::Role::SQLA2Passthrough to Makefile.PL no_index so the proof-of-concept role is not indexed under SQL-Abstract on CPAN
  • Refactor subclass method override grandfathering system
  • Remove old SQLA::More compat code (will restore a better set later)
  • Fix for empty 'order by' to ->select (dakkar)
  • Remove vestigial possibly-special-op name conversion, which stopped special_ops regexes matching op names containing underscores (RT#143837)
  • Fixes for _where_field_IN/BETWEEN overrides (jjatria)
  • Correctly handle literal passed to insert from/values key
  • Make puke() and belch() methods, ala the SQLA::Classic change
  • Syntax error fixes for 5.8 from ilmari

Modules

A test of future possibilities
Pretty Printing DebugObj UNAUTHORIZED
Generate SQL from Perl data structures
new/experimental additions to SQL::Abstract
Reference documentation for SQL::Abstract
helpful methods for plugin authors
Helper function for testing SQL::Abstract
Represent SQL as an AST

Provides

in maint/lib/Chunkstrumenter.pm
in lib/SQL/Abstract/Formatter.pm
in lib/SQL/Abstract/Parts.pm