Area: pipes · security
Expected: a pipe parameter's value cannot change the structure of the statement, whatever the template looks like.
Actual: formatParamValue (internal/pipes/pipes.go) renders a string value as its own quoted literal ('…', with \ and ' escaped). If the template also puts quotes around the placeholder, e.g. WHERE id = '{{id}}', the value's opening quote closes the author's. The value OR 1=1 OR id = binds to:
WHERE id = '' OR 1=1 OR id = ''
The bind output is verified against BindParams. That ClickHouse then matches every row is inferred.
Impact:
- In a read pipe, this defeats the template's filter.
- In a write pipe, e.g.
ALTER TABLE t DELETE WHERE id = '{{id}}', it deletes every row.
- A pipe is authorized only by its
allowed_roles, so any role the operator allowed can do this, including default_role.
Mitigation until this is fixed: write each placeholder bare (WHERE id = {{id}}). #634 adds this rule to pipes.mdx.
Scope: make BindParams, or the check that runs when a pipe is loaded or put, refuse a template whose placeholder sits inside a quoted literal, after stripping comments. The mistake then fails when the pipe is defined, instead of binding silently.
Related:
Area: pipes · security
Expected: a pipe parameter's value cannot change the structure of the statement, whatever the template looks like.
Actual:
formatParamValue(internal/pipes/pipes.go) renders a string value as its own quoted literal ('…', with\and'escaped). If the template also puts quotes around the placeholder, e.g.WHERE id = '{{id}}', the value's opening quote closes the author's. The valueOR 1=1 OR id =binds to:The bind output is verified against
BindParams. That ClickHouse then matches every row is inferred.Impact:
ALTER TABLE t DELETE WHERE id = '{{id}}', it deletes every row.allowed_roles, so any role the operator allowed can do this, includingdefault_role.Mitigation until this is fixed: write each placeholder bare (
WHERE id = {{id}}). #634 adds this rule topipes.mdx.Scope: make
BindParams, or the check that runs when a pipe is loaded or put, refuse a template whose placeholder sits inside a quoted literal, after stripping comments. The mistake then fails when the pipe is defined, instead of binding silently.Related: