The vulnerability is a classic SQL injection found in Ghost's Content API. The root cause lies in the slugFilterOrder function, which is responsible for generating a SQL ORDER BY clause based on a list of slugs provided in the filter query parameter. The provided patch commit, 30868d632b2252b638bc8a4c8ebf73964592ed91, clearly shows the vulnerable code and the subsequent fix.
In the vulnerable version, the slugFilterOrder function iterated through the slugs provided by the user and directly embedded them into the SQL string using template literals: order += \WHEN `${table}`.`slug` = '${slug}' THEN ${index} `;`. This direct concatenation without proper sanitization allowed for the injection of arbitrary SQL commands.
The fix involves refactoring the function to use parameterized queries. Instead of embedding the user input directly, the new code generates a SQL string with ? placeholders and passes the user-provided slugs as separate bindings. This ensures that the database treats the slug values strictly as data and not as executable SQL, thereby preventing the injection vulnerability. The changes in ghost/core/core/server/models/base/plugins/crud.js support this by allowing the model layer to accept and process these bindings along with the raw SQL.