chore(deps): strands-agents-tools 0.8.6 → 0.8.8 (calculator sandbox escape) - #1011
Merged
Conversation
…scape)
0.8.8 closes a sandbox escape in `strands_tools/calculator.py`. The AST
allowlist trusts string literals as positional arguments to a few
constructors that parse them as a plain name or numeric literal (Symbol,
symbols, Rational, Integer, Float). Through 0.8.6 that check ignored the
call's keywords, so `symbols('...', cls=N)` rerouted `symbols` to apply N —
and therefore sympify — to the string, re-parsing it outside the restricted
namespace. 0.8.8 adds `_has_only_assumption_keywords()`: a string positional
is trusted only when every keyword is a boolean assumption flag, and
`**kwargs` unpacking is untrusted because it can smuggle in `cls`.
This matters here because `calculator` is registered in
`create_default_registry()` and seeded `enabledByDefault=True`, so it is on
for every user and evaluates model-supplied expressions.
Verified by diffing the 0.8.6 and 0.8.8 wheels rather than trusting the
monorepo-wide release notes. Six files differ; we import only
`strands_tools.calculator`, whose diff is exactly this fix. The other five
(http_request, mem0_memory, mongodb_memory, think, use_aws) are unreachable
from our import graph.
Adds a regression test pinning the boundary to the installed wheel — it
fails on 0.8.6 and passes on 0.8.8, so a downgrade or resolver drift cannot
silently reopen the escape.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps
strands-agents-toolsfrom 0.8.6 to 0.8.8 (released 2026-09-04). One-line pin change plus the lockfile and a regression test.Why
0.8.8 closes a sandbox escape in
strands_tools/calculator.py.The calculator validates model-supplied expressions against an AST allowlist before parsing. That allowlist trusts a string literal only as a positional argument to constructors that parse it as a plain name or numeric literal —
Symbol,symbols,Rational,Integer,Float— which is what blocks thesympify-backed re-parse escape (N("..."),simplify("..."),solve("...")).Through 0.8.6 that check ignored the call's keyword arguments.
symbols('...', cls=N)reroutessymbolsto apply an arbitrary constructor — hereN— to the string, which re-parses it throughsympifyand escapes the restricted namespace.0.8.8 adds
_has_only_assumption_keywords(): a string positional is trusted only when every keyword on the call is a boolean assumption flag (Symbol('x', positive=True)).**kwargsunpacking (kw.arg is None) is treated as untrusted too, since it can smuggle incls.This is reachable by every user.
calculatoris registered increate_default_registry()(backend/src/agents/main_agent/tools/tool_registry.py:93) and seeded withenabledByDefault=True(backend/scripts/seed_bootstrap_data.py), so it is on by default and evaluates model-supplied input.Verification
Release notes for this package are monorepo-wide and unreliable, so this was verified by diffing the actual 0.8.6 and 0.8.8 wheels.
Six files differ:
calculator.py,http_request.py,mem0_memory.py,mongodb_memory.py,think.py,use_aws.py. We import onlystrands_tools.calculator— confirmed by grep, the sole import in the repo isfrom strands_tools.calculator import calculator, plus one mention inUSAGE_EXAMPLES.md. The other five are unreachable from our import graph, andcalculator.pyitself imports none of them. (strands_tools.browserexists but is unused and would need Playwright, which is deliberately not installed.)strands_tools/__init__.pyis byte-identical between the two versions.The
calculator.pydiff is exactly this fix — the new helper plus acontinueat the call site. Nothing else.Behavioural check against both versions:
symbols('x', cls=N)symbols('__import__("os").system("id")', cls=N)symbols('x', **kw)2 + 2 * 10,Symbol('x'),Rational('1/3')Through the real agent path (
create_default_registry()→calculator):2 + 2 * 10→Result: 22,sin(pi/2) + log(E)→Result: 2, andsymbols('x', cls=N)→{'status': 'error', ...'string literals are not supported'}.Full backend suite green: 7796 passed, 3 skipped, 0 failed.
Lockfile churn is minimal — only the
strands-agents-toolsentry moves; no transitive resolution changes. (0.8.8's metadata loosensrich<15→rich<16and theagent-core-*extras'bedrock-agentcorebound, but we install neither extra andrichdid not move.)Regression test
backend/tests/security/test_calculator_sandbox.py— a sibling to the existingtest_python_ast_policy.py, pinning the boundary to the installed wheel so a downgrade or resolver drift back below 0.8.8 fails the suite instead of silently reopening the escape. It fails on 0.8.6 (all 5 escape cases) and passes on 0.8.8.One test asserts the assumption-keyword carve-out against the validator rather than
parse_expression, becauseSymbol('x', positive=True)fails further downstream for an unrelated pre-existing reason: sympy'simplicit_multiplication_applicationtransform rewritespositive=Trueinto a multiplication beforeparse_exprsees it. Verified identical on 0.8.6 — not introduced by this bump.Scope
Deliberately kept to this one bump:
strands-agents==1.51.0untouched — a separate PR is taking that to 1.55.0 onfeature/strands-1-55-upgrade. Both touch adjacent lines inbackend/pyproject.toml, so expect a trivial conflict on whichever merges second; resolve by keeping both bumps.bedrock-agentcore==1.21.0untouched — 1.22.0 is entirely the unusedpayments/module.Noted, not addressed here
calculatoris marked deprecated upstream ("becomes an error log in v0.9.0", suggesting the vendedbashtool instead). This is pre-existing in 0.8.6, not new in 0.8.8, but it is worth a follow-up given we ship the tool on by default — the suggested replacement has a materially wider security boundary.backend/README.md:440still listsstrands-agents-tools 0.2.3, stale since well before this PR. Left alone to keep the diff to one logical change.Deploy
Merging to
developauto-deploys dev (backend.yml, frontend-deploy.yml, platform.yml are all push-triggered).🤖 Generated with Claude Code