You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
security(pipes): non-scalar pipe param values inlined into SQL unescaped + declared type unchecked (SQL injection) #317
Area: pipes · policy — security (SQL injection / escaping bypass) · found via pre-launch audit
Expected: the docs promise a pipe parameter value "can't break out of its literal and inject SQL," and a type: number parameter rejects a non-number.
Actual:internal/pipes/pipes.goformatParamValue — the default: branch (:230, fmt.Sprintf("%v", v)) emits raw, unescaped text. Scalar strings are escaped (\→\\, '→'') and scalar numbers are digits-only, so they're safe — but a JSON array or object value hits default: raw ([evil] / map[k:v]). BindParams reads only Required/Default and never checks ParamDef.Type, returning a nil bind slice (pure string interpolation, no driver ? params). internal/api/pipes.go decodes the POST into map[string]any and passes values verbatim; GET/POST /v1/pipes/{name} are outside RequireAdmin (authz is per-pipe allowed_roles, commonly [public] → unauthenticated). In a string-context pipe (WHERE col = '{{p}}') an array element's inner ' terminates the literal → clean UNION/boolean injection that bypasses the column allowlist.
Impact: latent on Stats today (the only parameterized pipe interpolates {{limit}} in a numeric LIMIT least({{limit}},50) context, so an array is a CH type error — yielding a full-pipe-SQL information disclosure in the echoed 500 rather than exfil), but one string-context public pipe away from a live unauth column-allowlist bypass. The structured-query path is unaffected (positional ? binds + per-column gating), so pipes are the one inlined-SQL surface. Re-verified fmt.Sprintf("%v") default branch on 40619b8a.
Scope: enforce ParamDef.Type in BindParams; escape or reject non-scalar values.
Related: #32 (this is the security core of Native SQL Templating — #32's own injection review only analyzed scalar inputs and missed the non-scalar breakout), the pipe cache-bypass issue.
From WaveHouse-Stats pre-launch security audit (WAVEHOUSE-FEEDBACK.md dogfooding), audited dev 60fed15; re-verified live on 40619b8a (2026-06-10). Full repro (payloads, local CH exfil of denied actor_id, live marker echo): docs/security/pipe-param-injection-poc.md (private). Filed via /pm-triage.
Activity