In storage/r2.rs, S3 credentials and URLs are interpolated directly into SQL statements via format!():
conn.execute_batch(&format!(
"SET s3_endpoint = '{}';
SET s3_access_key_id = '{}';
SET s3_secret_access_key = '{}';
SET s3_region = '{}';
SET s3_url_style = 'path';",
config.endpoint.trim_start_matches("https://"),
config.access_key_id,
config.secret_access_key,
config.region,
))?;
And again for the COPY and SELECT queries with s3_url.
If any of these values contains a single quote (unlikely for credentials but possible for bucket paths or user-controlled input), the SQL breaks or behaves unexpectedly. DuckDB's execute_batch doesn't use parameterized queries for SET statements, so this needs manual escaping at minimum.
The sources_to_array_literal function already does quote escaping for source names, so the pattern exists in the codebase - it just wasn't applied to the credential setup and S3 URL interpolation.
In
storage/r2.rs, S3 credentials and URLs are interpolated directly into SQL statements viaformat!():And again for the COPY and SELECT queries with
s3_url.If any of these values contains a single quote (unlikely for credentials but possible for bucket paths or user-controlled input), the SQL breaks or behaves unexpectedly. DuckDB's
execute_batchdoesn't use parameterized queries for SET statements, so this needs manual escaping at minimum.The
sources_to_array_literalfunction already does quote escaping for source names, so the pattern exists in the codebase - it just wasn't applied to the credential setup and S3 URL interpolation.