Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. From versio

## Unreleased

### Added

- Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359

## [14.1] - 2025-11-05

## Fixed
Expand Down
4 changes: 4 additions & 0 deletions docs/references/api/schemas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Schemas

PostgREST can expose a single or multiple schema's tables, views and functions. The :ref:`active database role <roles>` must have the usage privilege on the schemas to access them.

.. important::

Postgres system schemas ``pg_catalog`` and ``information_schema`` are not allowed in :ref:`db-schemas`. This is done to prevent leaking sensitive information and hence they cannot be accessed directly. As a workaround, we suggest that you create a view in your other exposed schema, which selects from these restricted schemas.

Single schema
-------------

Expand Down
15 changes: 13 additions & 2 deletions src/PostgREST/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl =
<*> (fromMaybe True <$> optBool "db-prepared-statements")
<*> (fmap toQi <$> optWithAlias (optString "db-root-spec")
(optString "root-spec"))
<*> (fromList . maybe ["public"] splitOnCommas <$> optWithAlias (optString "db-schemas")
(optString "db-schema"))
<*> parseDbSchemas "db-schemas" "db-schema"
<*> (fromMaybe True <$> optBool "db-config")
<*> (fmap toQi <$> optString "db-pre-config")
<*> parseTxEnd "db-tx-end" snd
Expand Down Expand Up @@ -329,6 +328,18 @@ parser optPath env dbSettings roleSettings roleIsolationLvl =
Just asp | asp == serverPort -> fail "admin-server-port cannot be the same as server-port"
| otherwise -> pure $ Just asp

parseDbSchemas :: C.Key -> C.Key -> C.Parser C.Config (NonEmpty Text)
parseDbSchemas k al =
optWithAlias (optString k) (optString al) >>= \case
Nothing -> pure $ fromList ["public"]
Just s
| "pg_catalog" `elem` schemas -> fail (errMsg "pg_catalog")
| "information_schema" `elem` schemas -> fail (errMsg "information_schema")
| otherwise -> pure $ fromList schemas
where
schemas = splitOnCommas s
errMsg x = ("db-schemas does not allow schema: '" <> x <> "'")

parseSocketFileMode :: C.Key -> C.Parser C.Config FileMode
parseSocketFileMode k =
optString k >>= \case
Expand Down
4 changes: 4 additions & 0 deletions test/io/fixtures/fixtures.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,7 @@ specialhostvalues:
- '*6'
- '!6'
- '*'

restrictedschemas:
- 'pg_catalog'
- 'information_schema'
17 changes: 17 additions & 0 deletions test/io/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,23 @@ def test_jwt_secret_min_length(defaultenv):
assert "The JWT secret must be at least 32 characters long." in error


@pytest.mark.parametrize("restricted_schema", FIXTURES["restrictedschemas"])
def test_restricted_db_schemas(restricted_schema, defaultenv):
"Should print error when db-schemas config contain pg_catalog or information_schema"

# test when one schema is given in db-schemas
env = {**defaultenv, "PGRST_DB_SCHEMAS": restricted_schema}

error = cli(["--dump-config"], env=env, expect_error=True)
assert f"db-schemas does not allow schema: '{restricted_schema}'" in error

# test when multiple schemas are given in db-schemas
env = {**defaultenv, "PGRST_DB_SCHEMAS": f"test, {restricted_schema}"}

error = cli(["--dump-config"], env=env, expect_error=True)
assert f"db-schemas does not allow schema: '{restricted_schema}'" in error


# TODO: Improve readability of "--ready" healthcheck tests
@pytest.mark.parametrize("host", ["127.0.0.1", "::1"], ids=["IPv4", "IPv6"])
def test_cli_ready_flag_success(host, defaultenv):
Expand Down