Skip to content

fix(bigtable): stop resolving view parameters from caller-writable state - #7132

Closed
prasanna8585 wants to merge 3 commits into
google:mainfrom
prasanna8585:fix/bigtable-view-parameter-state-fallback
Closed

prasanna8585 wants to merge 3 commits into
google:mainfrom
prasanna8585:fix/bigtable-view-parameter-state-fallback

Conversation

@prasanna8585

@prasanna8585 prasanna8585 commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

BigtableParameterizedViewTool wraps Bigtable's execute_sql to automatically inject values (like user_id) into a parameterized view's VIEW_PARAMETERS(), so the view itself can restrict which rows a query is allowed to see. The class's own docstring states this "securely restricts query execution to the logged-in user's data" -- but the resolution logic had an undocumented fallback: when a configured view_parameter_name did not match a strongly-typed attribute of tool_context (which user_id always does, via ReadonlyContext), it fell back to tool_context.state[param_name].

tool_context.state is writable by the caller -- the same fact this same PR's sibling fix (BigQuery/AgentEngineSandboxComputer, in query_tool.py and sandbox_computer.py) already established for a different pair of tools in this same file tree. A view parameter taken from state lets the caller choose which user's (or tenant's) rows a "securely restricted" parameterized view returns, defeating the row- level restriction the feature exists to provide. This is realistic for any application-defined scoping parameter beyond the documented user_id example -- tenant_id, org_id, customer_id, or any other custom name a multi-tenant deployment configures via view_parameter_names, none of which are built-in ToolContext/ReadonlyContext attributes.

Verified this was never previously addressed: the feature was introduced in 14a24f2 (PR #6128, "Support parameterized views with secure parameter injection") and has had no subsequent fix; the only later commit touching this file is an unrelated mypy-typing refactor.

Fix: remove the tool_context.state fallback entirely. Only names that resolve to a real tool_context attribute are honored now; anything else is silently omitted from view_parameters, exactly as an already- missing attribute was previously handled.

Verified: existing test suite (14 tests) run and pass, including the two pre-existing tests that only exercise the safe, strongly-typed path (user_id), which are unaffected. The test that asserted the vulnerable fallback behavior (test_bigtable_parameterized_view_tool_execution_session_state_fallback) is replaced with test_bigtable_parameterized_view_tool_ignores_state_for_custom_parameters, asserting the opposite: a caller-controlled tenant_id sitting in session state is not used. Confirmed this new test actually catches the bug by temporarily reverting the fix locally and re-running it -- it fails against the vulnerable code and passes against the fix. test_bigtable_parameterized_view_tool_execution_multiple_parameters is updated to match: tenant_id/agent_id (state-only) are now correctly omitted from the result, while user_id (a real attribute) still resolves.

BigtableParameterizedViewTool wraps Bigtable's execute_sql to
automatically inject values (like user_id) into a parameterized view's
VIEW_PARAMETERS(), so the view itself can restrict which rows a query
is allowed to see. The class's own docstring states this "securely
restricts query execution to the logged-in user's data" -- but the
resolution logic had an undocumented fallback: when a configured
view_parameter_name did not match a strongly-typed attribute of
tool_context (which user_id always does, via ReadonlyContext), it fell
back to tool_context.state[param_name].

tool_context.state is writable by the caller -- the same fact this
same PR's sibling fix (BigQuery/AgentEngineSandboxComputer, in
query_tool.py and sandbox_computer.py) already established for a
different pair of tools in this same file tree. A view parameter taken
from state lets the caller choose which user's (or tenant's) rows a
"securely restricted" parameterized view returns, defeating the row-
level restriction the feature exists to provide. This is realistic for
any application-defined scoping parameter beyond the documented
user_id example -- tenant_id, org_id, customer_id, or any other custom
name a multi-tenant deployment configures via view_parameter_names,
none of which are built-in ToolContext/ReadonlyContext attributes.

Verified this was never previously addressed: the feature was
introduced in 14a24f2 (PR google#6128, "Support parameterized views with
secure parameter injection") and has had no subsequent fix; the only
later commit touching this file is an unrelated mypy-typing refactor.

Fix: remove the tool_context.state fallback entirely. Only names that
resolve to a real tool_context attribute are honored now; anything
else is silently omitted from view_parameters, exactly as an already-
missing attribute was previously handled.

Verified: existing test suite (14 tests) run and pass, including the
two pre-existing tests that only exercise the safe, strongly-typed
path (user_id), which are unaffected. The test that asserted the
vulnerable fallback behavior
(test_bigtable_parameterized_view_tool_execution_session_state_fallback)
is replaced with
test_bigtable_parameterized_view_tool_ignores_state_for_custom_parameters,
asserting the opposite: a caller-controlled tenant_id sitting in
session state is not used. Confirmed this new test actually catches
the bug by temporarily reverting the fix locally and re-running it --
it fails against the vulnerable code and passes against the fix.
test_bigtable_parameterized_view_tool_execution_multiple_parameters is
updated to match: tenant_id/agent_id (state-only) are now correctly
omitted from the result, while user_id (a real attribute) still
resolves.
@prasanna8585
prasanna8585 force-pushed the fix/bigtable-view-parameter-state-fallback branch from 3508570 to be5a66e Compare September 23, 2026 05:53
copybara-service Bot pushed a commit that referenced this pull request Oct 19, 2026
Merge #7132

View parameters are no longer resolved from tool_context.state to prevent
caller or model tampering. Callers configuring custom view parameters can
supply them via view_parameters on BigtableToolset or BigtableParameterizedViewTool
(supporting a mapping or a per-invocation resolver callable).

PiperOrigin-RevId: 1002437706
@adk-bot

adk-bot commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Thank you @prasanna8585 for your contribution! 🎉

Your changes have been successfully imported and merged via Copybara in commit 57e8bc6.

Closing this PR as the changes are now in the main branch.

@adk-bot adk-bot added the merged [Status] This PR is merged label Oct 19, 2026
@adk-bot adk-bot closed this Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged [Status] This PR is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants