Security fix — Critical
Residual RCE bypass of the CVE-2026-55546 (GHSA-mw6r-2hvm-4rp2) fix, reported under GHSA-2p69-jpm6-jrxh.
The v0.2.1 denylist in safe_parser.py only matched literal dunder strings, so it could be evaded with:
- unlisted dunders (
__getattribute__,__func__,__call__) - string-literal splitting (
'__glo'+'bals'+'__') - attribute-walkable objects in the eval namespace (
sqrt,cbrt)
This allowed code execution via the verify_math_expression MCP tool.
Hardening (v0.2.2)
- AST node allowlist before
parse_expr— only arithmetic nodes survive;Attribute,Subscript,Lambda, comprehensions rejected - String/bytes constants rejected — removes the concatenation gadget class
- NFKC normalization — blocks PEP 3131 unicode-dunder bypass
- Implicit-multiplication guard — non-Python input (
2x,sin x) gets a strict charset (no quotes/brackets;.only as decimal point) - Regex denylist retained as defense-in-depth
- 27 regression tests (11 attack variants blocked, 16 legit math forms preserved)
Credits
- Lx 🎀 (@Lxcardoza993) — responsible disclosure, root-cause analysis, PoC, and the AST-gate approach
Compatibility
No breaking changes to legit math: sqrt(4), 2x, sin x, x^2, 2.5x, 2(x+1), factorial(5) all behave as before. Full suite: 114 tests passing.
Upgrade
pip install --upgrade qwed-mcp==0.2.2Full Changelog: v0.2.1...v0.2.2