← back to Cli Printing Press
fix(cli): validate ListIDs resourceType to close SQL injection (#1000)
242a56bc6a2d88cc8b93ac29d90254a7f7d6e1e9 · 2026-05-11 10:48:01 -0400 · brennaman
* fix(cli): validate ListIDs resourceType to close SQL injection
Store.ListIDs previously interpolated resourceType directly into the
SELECT, allowing a crafted value to read or corrupt the database.
Resolve the table name via a parameterized sqlite_master lookup and
substitute only the trusted name (double-quoted) into the query;
fall back to the generic resources table when the lookup misses.
Mirrored into the outlook-calendar PR (mvanhorn/printing-press-library#408)
so this PR ships clean; every future regen now picks up the fix too.
* Update internal/generator/templates/store.go.tmpl
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: Trevin Chow <trevin@trevinchow.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Files touched
M internal/generator/templates/store.go.tmpl
Diff
commit 242a56bc6a2d88cc8b93ac29d90254a7f7d6e1e9
Author: brennaman <4397563+brennaman@users.noreply.github.com>
Date: Mon May 11 10:48:01 2026 -0400
fix(cli): validate ListIDs resourceType to close SQL injection (#1000)
* fix(cli): validate ListIDs resourceType to close SQL injection
Store.ListIDs previously interpolated resourceType directly into the
SELECT, allowing a crafted value to read or corrupt the database.
Resolve the table name via a parameterized sqlite_master lookup and
substitute only the trusted name (double-quoted) into the query;
fall back to the generic resources table when the lookup misses.
Mirrored into the outlook-calendar PR (mvanhorn/printing-press-library#408)
so this PR ships clean; every future regen now picks up the fix too.
* Update internal/generator/templates/store.go.tmpl
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: Trevin Chow <trevin@trevinchow.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---
internal/generator/templates/store.go.tmpl | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/internal/generator/templates/store.go.tmpl b/internal/generator/templates/store.go.tmpl
index a022117d..e86553d7 100644
--- a/internal/generator/templates/store.go.tmpl
+++ b/internal/generator/templates/store.go.tmpl
@@ -1041,11 +1041,21 @@ func (s *Store) GetSyncCursor(resourceType string) string {
// ListIDs returns all IDs from a resource's domain table, or from the generic
// resources table if no domain table exists. Used by dependent sync to iterate parents.
+//
+// resourceType is never interpolated into SQL directly. We resolve it to a real
+// table name via a parameterized sqlite_master lookup; only that trusted name is
+// substituted (double-quoted) into the SELECT. Callers may pass any string.
func (s *Store) ListIDs(resourceType string) ([]string, error) {
- // Try domain table first (tables are named after the resource type)
- query := fmt.Sprintf("SELECT id FROM %s", resourceType)
- rows, err := s.db.Query(query)
- if err != nil {
+ var table string
+ err := s.db.QueryRow(
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
+ resourceType,
+ ).Scan(&table)
+ var rows *sql.Rows
+ if err == nil && table != "" {
+ rows, err = s.db.Query(fmt.Sprintf(`SELECT id FROM "%s"`, strings.ReplaceAll(table, `"`, `""`)))
+ }
+ if err != nil || table == "" {
// Fall back to generic resources table
rows, err = s.db.Query("SELECT id FROM resources WHERE resource_type = ?", resourceType)
if err != nil {
← 76db1cc4 chore(main): release 4.3.0 (#898)
·
back to Cli Printing Press
·
fix(cli): emit --body-json fallback for oneOf/anyOf request 910c228d →