Skip to content

fix: sanitize array elements in list_condition_expr to prevent SQL injection#1713

Open
prabhaks wants to merge 4 commits into
parseablehq:mainfrom
prabhaks:fix/sql-injection-list-condition-expr
Open

fix: sanitize array elements in list_condition_expr to prevent SQL injection#1713
prabhaks wants to merge 4 commits into
parseablehq:mainfrom
prabhaks:fix/sql-injection-list-condition-expr

Conversation

@prabhaks

@prabhaks prabhaks commented Jul 2, 2026

Copy link
Copy Markdown

Summary

Fixes #1688

list_condition_expr in src/alerts/alerts_utils.rs was interpolating inner_value directly into ARRAY[...] SQL expressions without any escaping or validation. This allowed crafted input like 1] OR 1=1; -- to break out of the ARRAY context and inject arbitrary SQL.

scalar_condition_expr right below it already handled this correctly (single-quote escaping, numeric/boolean validation). This PR brings list_condition_expr to the same standard.

Note: get_filter_string is a structural joiner only and handles no values directly. scalar_condition_expr already had correct escaping in place — this PR intentionally leaves both untouched.

Changes

Added a sanitize_array_elements helper that:

  • Splits the comma-separated array value into individual elements
  • Validates each element as a numeric literal, boolean literal, or properly single-quoted string
  • Rejects any element containing bracket characters [ or ] that could escape the ARRAY[...] context
  • Returns an Err describing the first offending element if validation fails

list_condition_expr now passes inner_value through this helper before interpolating it into the SQL format string.

Testing

  • Existing alert condition tests pass
  • Manually verified that 1] OR 1=1; -- now returns an error instead of being interpolated
  • Valid numeric, boolean, and quoted string array values still produce correct SQL
  • Unit tests added for sanitize_array_elements and list_condition_expr

References

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of list-based filters to safely process comma-separated values.
    • Added stronger validation to prevent malformed or unsafe array input from being used in filtering.
    • Preserved support for numeric, boolean, and quoted string values while correctly escaping special characters.
    • Continued to reject unsupported filter operators and invalid bracket-based input.

…jection

Closes parseablehq#1688

The list_condition_expr function was interpolating inner_value directly
into ARRAY[...] SQL expressions without any escaping or validation,
allowing crafted input like `1] OR 1=1; --` to break out of the ARRAY
context and inject arbitrary SQL.

scalar_condition_expr already handled escaping correctly (single-quote
escaping, numeric/boolean validation). This commit brings list_condition_expr
to the same standard by adding a sanitize_array_elements helper that:
- Splits the value by comma
- Validates each element as numeric, boolean, or a properly single-quoted string
- Rejects any element containing bracket characters `[` or `]` that could
  escape the ARRAY literal context
- Returns an Err if any element fails validation
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a new sanitize_array_elements function in alerts_utils.rs that validates and escapes comma-separated array elements before interpolation into SQL ARRAY[...] literals, rejecting bracket characters and escaping quotes. list_condition_expr now uses this sanitizer instead of directly interpolating raw values. Includes new unit tests.

Changes

Array Element Sanitization

Layer / File(s) Summary
Sanitizer implementation and integration
src/alerts/alerts_utils.rs
New sanitize_array_elements helper rejects bracket characters, escapes single quotes for bare and pre-quoted strings, and returns sanitized comma-joined output; list_condition_expr now sanitizes inner_value elements and interpolates the resulting safe_value into Contains/DoesNotContain/Equal/NotEqual SQL expressions instead of the raw value.
Sanitizer and condition expression tests
src/alerts/alerts_utils.rs
New test module validates numeric, boolean, bare-string, and pre-quoted-string sanitization, single-quote escaping, bracket-based injection rejection, list_condition_expr output formatting and bracket stripping, and error behavior for injection attempts and unsupported operators.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit guards the ARRAY gate,
No stray bracket slips past the fence of fate,
Quotes get doubled, brackets denied,
Injection attempts are turned aside,
Hop, hop, hooray — the query's safe tonight! 🐰🛡️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: sanitizing array elements in list_condition_expr to prevent SQL injection.
Description check ✅ Passed The description covers the issue reference, problem statement, chosen fix, testing, and references, which is mostly complete for this template.
Linked Issues check ✅ Passed The PR addresses the reported SQL injection in list_condition_expr by sanitizing array elements and adding tests for the exploit case.
Out of Scope Changes check ✅ Passed The changes stay focused on alerts_utils.rs sanitization and related tests, with no clear unrelated scope added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@prabhaks

prabhaks commented Jul 2, 2026

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

nitisht added a commit to parseablehq/.github that referenced this pull request Jul 2, 2026
prabhaks added 3 commits July 1, 2026 22:41
The bare unquoted string branch was rejecting valid values containing
spaces, colons, slashes, etc. due to an alphanumeric-only allowlist.

This is inconsistent with scalar_condition_expr which accepts any string
and simply escapes single quotes. The bracket character check at the top
already covers the actual injection vector, making the allowlist redundant.

Now mirrors scalar_condition_expr: escape single quotes and wrap in
single quotes, no character allowlist.
The contains("' OR '") check was a false negative — the correctly
escaped output 'foo'' OR ''1''=''1' still contains that substring
as part of the doubled quotes. The assert_eq on the exact escaped
string is already sufficient to prove injection safety; drop the
redundant contains check.
@prabhaks prabhaks marked this pull request as ready for review July 2, 2026 06:41
@prabhaks

prabhaks commented Jul 2, 2026

Copy link
Copy Markdown
Author

@nikhilsinhaparseable please review the changes whenever you get the chance. Tested locally - runs fine!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/alerts/alerts_utils.rs`:
- Around line 473-514: The array sanitizer in sanitize_array_elements currently
splits on every comma, which breaks quoted list items containing commas. Update
the parsing logic to be quote-aware so elements like single-quoted strings with
embedded commas stay intact, while preserving the existing trimming, bracket
rejection, and re-quoting behavior used by sanitize_array_elements and
scalar_condition_expr.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ddef110e-7b9c-401a-b0ae-e26f8bd24a62

📥 Commits

Reviewing files that changed from the base of the PR and between 6dae911 and 75e9a70.

📒 Files selected for processing (1)
  • src/alerts/alerts_utils.rs

Comment on lines +473 to +514
fn sanitize_array_elements(value: &str) -> Result<String, String> {
let sanitized: Result<Vec<String>, String> = value
.split(',')
.map(|elem| {
let elem = elem.trim();

// Reject bracket characters that could escape the ARRAY[...] context.
// This is the primary injection guard; the quoting logic below is
// consistent with scalar_condition_expr and does not rely on this check.
if elem.contains('[') || elem.contains(']') {
return Err(format!(
"Invalid array element: '{elem}' contains bracket characters"
));
}

// Numeric literal — pass through as-is
if elem.parse::<f64>().is_ok() {
return Ok(elem.to_string());
}

// Boolean literal — pass through as-is
if elem.parse::<bool>().is_ok() {
return Ok(elem.to_string());
}

// Single-quoted string — strip outer quotes, re-escape internals, re-wrap.
// Mirrors how scalar_condition_expr handles the Some(_) column_type branch.
if elem.starts_with('\'') && elem.ends_with('\'') && elem.len() >= 2 {
let inner = &elem[1..elem.len() - 1];
let escaped = inner.replace('\'', "''");
return Ok(format!("'{escaped}'"));
}

// Bare unquoted string — escape single quotes and wrap in single quotes.
// Mirrors the ValueType::String arm in scalar_condition_expr (None branch):
// format!("'{}'", val.replace("'", "''"))
Ok(format!("'{}'", elem.replace('\'', "''")))
})
.collect();

Ok(sanitized?.join(", "))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find how list-type condition values are constructed/serialized to gauge whether
# a single element can contain a comma (e.g., quoted string values).
rg -nP -C3 '\blist\b|ARRAY\[|column_type' src/alerts/ src/handlers/http/query_context.rs

Repository: parseablehq/parseable

Length of output: 2061


Use quote-aware splitting for list values. value.split(',') breaks quoted elements containing commas, so a single input like 'New York, NY' is turned into multiple array entries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/alerts/alerts_utils.rs` around lines 473 - 514, The array sanitizer in
sanitize_array_elements currently splits on every comma, which breaks quoted
list items containing commas. Update the parsing logic to be quote-aware so
elements like single-quoted strings with embedded commas stay intact, while
preserving the existing trimming, bracket rejection, and re-quoting behavior
used by sanitize_array_elements and scalar_condition_expr.

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.

Security: SQL injection risk in get_filter_string / list_condition_expr (alerts_utils.rs)

1 participant