Skip to content

Conversation

@amacneil
Copy link
Owner

@amacneil amacneil commented Jan 27, 2026

Strip psql meta-commands from schema files to fix dbmate load failures on newer PostgreSQL versions.

PostgreSQL 15.14+/16.10+/17.6+ pg_dump outputs \restrict and \unrestrict commands as a security measure (CVE-2025-8714). These are psql client meta-commands, not SQL statements, causing sqlDB.Exec() to fail with a syntax error when dbmate load attempts to execute them directly against the database server. This PR adds a filter to remove these lines before execution.

Fixes #735


Note

Ensures dbmate load ignores psql meta-commands produced by newer pg_dump so schema loads don’t fail.

  • Adds dbutil.StripPsqlMetaCommands to remove lines starting with \ (e.g., \restrict, \unrestrict) from SQL input
  • Invokes this filter in DB.LoadSchema() before executing schema.sql
  • Adds unit tests covering stripping behavior and non-stripping of normal SQL

Written by Cursor Bugbot for commit ec8d54c. This will update automatically on new commits. Configure here.

PostgreSQL 15.14+/16.10+/17.6+ pg_dump adds \restrict and \unrestrict
psql meta-commands to schema dumps as a security measure (CVE-2025-8714).
These commands cannot be executed directly against the PostgreSQL server
via sqlDB.Exec(), causing 'syntax error at or near "\"' when running
dbmate load.

Add StripPsqlMetaCommands() function to remove all psql meta-commands
(lines starting with backslash) before executing the schema SQL.

Fixes #735

Co-authored-by: adrian <adrian@foxglove.dev>
@cursor
Copy link

cursor bot commented Jan 27, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@amacneil amacneil changed the title Issue 735 reproduction Jan 27, 2026
@amacneil amacneil marked this pull request as ready for review January 27, 2026 17:10
@amacneil
Copy link
Owner Author

@stevenringo want to test this branch?

@amacneil
Copy link
Owner Author

Works for me.

Before:

root@4efda5872260:/src/testdata# ../dist/dbmate -e POSTGRES_TEST_URL load
Reading: ./db/schema.sql
Error: pq: syntax error at or near "\"

After:

root@4efda5872260:/src/testdata# ../dist/dbmate -e POSTGRES_TEST_URL load
Reading: ./db/schema.sql
@amacneil amacneil requested a review from dossy January 27, 2026 20:04
Copy link
Collaborator

@dossy dossy left a comment

Choose a reason for hiding this comment

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

I think this is fine, although it might be useful to disclaim that this dbutil.StripPsqlMetaCommands() is a very naive implementation, because there are certainly valid SQL inputs to psql that it will get wrong.

# dist/dbmate -e POSTGRES_TEST_URL create
Creating: dbmate_test

# cat >test.sql <<-'EOT'
> create table t (x text);
> insert into t (x) values ('postgres understands
> \how to parse this');
> EOT

# cat test.sql
create table t (x text);
insert into t (x) values ('postgres understands
\how to parse this');

# psql $POSTGRES_TEST_URL < test.sql
CREATE TABLE
INSERT 0 1

# psql $POSTGRES_TEST_URL -c 'select * from t'
          x
----------------------
 postgres understands+
 \how to parse this
(1 row)

# dist/dbmate -e POSTGRES_TEST_URL drop
Dropping: dbmate_test

# dist/dbmate -e POSTGRES_TEST_URL create
Creating: dbmate_test

# dist/dbmate -e POSTGRES_TEST_URL --schema-file test.sql load
Reading: test.sql
Error: pq: unterminated quoted string at or near "'postgres understands
"

As long as the expectation is that dbmate load is only used to execute DDL statements which are highly unlikely to have embedded newlines in string values, then we're fine.

To illustrate what I mean:

# cat >test2.sql <<-'EOT'
> create table bozo (x text default 'only a bozo
> \would do this');
> EOT

# cat test2.sql
create table bozo (x text default 'only a bozo
\would do this');

# dist/dbmate -e POSTGRES_TEST_URL drop
Dropping: dbmate_test

# dist/dbmate -e POSTGRES_TEST_URL create
Creating: dbmate_test

# psql $POSTGRES_TEST_URL < test2.sql
CREATE TABLE

# psql $POSTGRES_TEST_URL -c '\dS bozo'
                     Table "public.bozo"
 Column | Type | Collation | Nullable |        Default
--------+------+-----------+----------+-----------------------
 x      | text |           |          | 'only a bozo         +
        |      |           |          | \would do this'::text

# dist/dbmate -e POSTGRES_TEST_URL drop
Dropping: dbmate_test

# dist/dbmate -e POSTGRES_TEST_URL create
Creating: dbmate_test

# dist/dbmate -e POSTGRES_TEST_URL --schema-file test2.sql load
Reading: test2.sql
Error: pq: unterminated quoted string at or near "'only a bozo
"

Such an unlikely edge case. If someone actually gets bitten by this, we can all point back at this comment and laugh about it.

@stevenringo
Copy link

I still don't really understand how the implementation mitigates anything. And also, shouldn't the underlying Go library be handling this? (sorry, not a Go developer)

Add comments clarifying that this is a naive line-based implementation
that works for pg_dump output but could theoretically break on hand-crafted
SQL with multi-line strings containing backslashes at line start.

Co-authored-by: adrian <adrian@foxglove.dev>
@amacneil
Copy link
Owner Author

@dossy thanks, I added some more comments to document those limitations

@amacneil amacneil merged commit 151de82 into main Jan 28, 2026
11 checks passed
@amacneil amacneil deleted the cursor/issue-735-reproduction-d7ee branch January 28, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

5 participants