This is an automated email from the ASF dual-hosted git repository.
kaxil pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 0bae39f4884 Document that `SQLToolset` does not check functions
without `allowed_tables` (#74444)
0bae39f4884 is described below
commit 0bae39f4884bfd5b7434c0ece438860aa438999d
Author: Wei Lee <[email protected]>
AuthorDate: Sat Oct 10 21:18:49 2026 +0900
Document that `SQLToolset` does not check functions without
`allowed_tables` (#74444)
* Document that SQLToolset does not check functions without allowed_tables
Without allowed_tables, a SELECT can still call side-effecting functions
such as nextval or pg_terminate_backend. Recommend a least-privilege role.
* Clarify SQLToolset read-only guidance and allowed_tables function check
- Recommend a least-privilege role together with a read-only role/session
default, and note that a transaction cannot be set from the Dag.
- State that the allowed_tables function check rejects only functions
sqlglot cannot type, so typed syntax such as T-SQL NEXT VALUE FOR or
Snowflake seq.nextval still passes.
---
providers/common/ai/docs/agent_security.rst | 12 +++++++++++-
providers/common/ai/docs/toolsets/sql.rst | 16 ++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/providers/common/ai/docs/agent_security.rst
b/providers/common/ai/docs/agent_security.rst
index 08a6fbd96a5..d5e1a07ae22 100644
--- a/providers/common/ai/docs/agent_security.rst
+++ b/providers/common/ai/docs/agent_security.rst
@@ -112,7 +112,17 @@ No single layer is sufficient on its own. They work
together.
(``DESCRIBE``/``SHOW``) statements pass; INSERT, UPDATE, DELETE, DROP,
and writes hidden behind ``EXPLAIN`` are rejected.
- Does not prevent the agent from reading sensitive data that the
- database user has SELECT access to.
+ database user has SELECT access to. Without ``allowed_tables`` the
check is
+ statement-level only: a side-effecting function inside a SELECT
+ (``nextval``, ``pg_terminate_backend``, ``dblink_exec``) is not blocked.
+ Setting ``allowed_tables`` adds a function check, but it rejects only
functions
+ sqlglot cannot type; typed syntax such as T-SQL ``NEXT VALUE FOR`` or
Snowflake
+ ``seq.nextval`` still passes. Use a least-privilege role and, where the
database
+ supports it, a read-only default for that role or session (for example
+ ``ALTER ROLE <role> SET default_transaction_read_only = on`` on
PostgreSQL).
+ The toolset opens its own connection per call, so you cannot set a
transaction
+ from the Dag, and a read-only setting is defense in depth: it does not
stop every
+ side-effecting function.
* - **DataFusionToolset: read-only by default**
- ``allow_writes=False`` (default) validates every SQL query through
``validate_sql()`` and rejects CREATE TABLE, CREATE VIEW, INSERT
diff --git a/providers/common/ai/docs/toolsets/sql.rst
b/providers/common/ai/docs/toolsets/sql.rst
index 93b16520943..df0a4caca78 100644
--- a/providers/common/ai/docs/toolsets/sql.rst
+++ b/providers/common/ai/docs/toolsets/sql.rst
@@ -67,6 +67,22 @@ rejects by scanning the parsed statement for write
operations. When
table, so its target must be on the list, while ``SHOW`` enumerates objects
beyond
any single table and is rejected outright (see
:ref:`allowed-tables-enforcement`).
+The read-only check inspects statement types, not what a function does. By
default
+(no ``allowed_tables``) a function call inside a ``SELECT`` is not examined, so
+``SELECT nextval('seq')``, ``SELECT pg_terminate_backend(pid)`` or
+``SELECT dblink_exec(...)`` pass validation and run with the connection's
+privileges. Setting ``allowed_tables`` turns on the function check: every
function
+sqlglot cannot type is rejected unless it is listed in ``allowed_functions``.
The
+check rejects only functions sqlglot cannot type; typed syntax such as T-SQL
+``NEXT VALUE FOR seq`` or Snowflake ``seq.nextval`` still passes, so
+``allowed_tables`` is not a guarantee against side-effecting functions. Either
way,
+point the connection at a least-privilege role and, where the database
supports it,
+a read-only default for that role or session (for example
+``ALTER ROLE <role> SET default_transaction_read_only = on`` on PostgreSQL).
The
+toolset opens its own connection per call, so you cannot set a transaction
from the
+Dag, and a read-only setting is defense in depth: it does not stop every
+side-effecting function.
+
.. _sql-toolset-restricted:
Restricting the agent