QWED-MCP Audit Finding: HIGH-05
Severity: π HIGH
Component: safe_parser.py (approved boundary) + math_engine.py + tools.py (execution sandbox)
Audit ID: HIGH-05
Re-audit of v0.2.1: Finding is NEW β distinct from fixed #10 (execution timeout) and from GHSA-mw6r-2hvm-4rp2 (CWE-94)
Description
GHSA-mw6r-2hvm-4rp2 fixed code execution (CWE-94) in the SymPy parser path. The same sink family remains open for resource exhaustion (CWE-400): SymPy eagerly evaluates integer Pow and factorial, and the denylist does not constrain operand magnitude.
Empirically confirmed on v0.2.1:
safe_parse_expr("10**10**6")
# -> sympy.Integer with bit_length = 3,321,929 (~415 KB) β FULLY evaluated in memory
Therefore:
| Payload |
Effect |
Denylist result |
10**10**10 |
~4 GB integer computation β host OOM |
β
passes |
factorial(10**9) |
~8.5 billion digits β host OOM |
β
passes |
10**9 ** (10**9) variants |
unbounded allocation |
β
passes |
The 5,000-char length cap does not help β the payloads above are under 20 chars.
Compounding factor: the execution subprocess in execute_python_code_tool has no memory limits (no resource.setrlimit, no cgroup constraint). The 30s foreground / 120s background timeouts (fix for #10) do not help because the allocation completes in well under a second β the OOM killer (or host swap death) fires before the timeout does.
Additionally, math_engine.verify_math_expression runs simplify(actual - claimed) with no operation-level bound. Pathological inputs (simplify on adversarial expressions is a known SymPy CPU sink) give each request up to 30s of free CPU burn inside the semaphore window.
Why This Violates QWED Philosophy
- Principle 11 β Vulnerability Family Thinking: The GHSA fix patched one vulnerability class at the sink (code execution) and left the adjacent class (resource exhaustion) open at the same sink. Per Principle 11, the fix is incomplete while equivalent-impact paths remain.
- Principle 2 β Fail Closed: An unverifiable resource cost is currently accepted by default. Inputs whose evaluation cost cannot be bounded must be rejected.
Expected Behavior
- Evaluation cost must be bounded before evaluation. Deterministic options:
- Cap exponent operands in
Pow with integer base/exponent above a threshold (e.g., reject a**b when b > 10_000 and a > 1 β the result would exceed ~33k bits).
- Cap
factorial(n) at a fixed n ceiling (e.g., n <= 10_000).
- Reject nested power towers beyond depth 2 with integer operands.
- The execution subprocess must have a memory ceiling (
resource.setrlimit(RLIMIT_AS, ...) on POSIX; Job Objects on Windows) so a blowout kills the child, not the host.
- Math engine operations (
diff, integrate, simplify, solve) should run under an operation-level deadline so a single request cannot consume the entire tool-call window in CPU.
Suggested Fix Direction
# In safe_parser.py β AST-level pre-flight after parse, before return
import sympy
_MAX_POW_EXPONENT = 10_000
_MAX_FACTORIAL_ARG = 10_000
def _enforce_cost_bounds(expr):
for node in sympy.preorder_traversal(expr):
if isinstance(node, sympy.Pow) and node.exp.is_Integer:
if abs(int(node.exp)) > _MAX_POW_EXPONENT and node.base != 1:
raise SafeParserError("Exponent exceeds deterministic cost bound")
if isinstance(node, sympy.factorial) and node.args[0].is_Integer:
if int(node.args[0]) > _MAX_FACTORIAL_ARG:
raise SafeParserError("factorial argument exceeds deterministic cost bound")
return expr
Note: bounds must be enforced on the parsed expression (post-parse_expr), which means parse_expr itself must not eagerly evaluate β use evaluate=False where supported, or pre-scan operand magnitudes with a regex/AST pass before calling parse_expr. Whichever route is chosen, the invariant is: no eager evaluation of unbounded-magnitude operands.
Environment
| Field |
Value |
| QWED-MCP Version |
0.2.1 |
| Component |
Parser Boundary + Math Engine + Execution Sandbox |
| Files |
src/qwed_mcp/engines/safe_parser.py, src/qwed_mcp/engines/math_engine.py, src/qwed_mcp/tools.py |
QWED-MCP Audit Finding: HIGH-05
Severity: π HIGH
Component:
safe_parser.py(approved boundary) +math_engine.py+tools.py(execution sandbox)Audit ID: HIGH-05
Re-audit of v0.2.1: Finding is NEW β distinct from fixed #10 (execution timeout) and from GHSA-mw6r-2hvm-4rp2 (CWE-94)
Description
GHSA-mw6r-2hvm-4rp2 fixed code execution (CWE-94) in the SymPy parser path. The same sink family remains open for resource exhaustion (CWE-400): SymPy eagerly evaluates integer
Powandfactorial, and the denylist does not constrain operand magnitude.Empirically confirmed on v0.2.1:
Therefore:
10**10**10factorial(10**9)10**9 ** (10**9)variantsThe 5,000-char length cap does not help β the payloads above are under 20 chars.
Compounding factor: the execution subprocess in
execute_python_code_toolhas no memory limits (noresource.setrlimit, no cgroup constraint). The 30s foreground / 120s background timeouts (fix for #10) do not help because the allocation completes in well under a second β the OOM killer (or host swap death) fires before the timeout does.Additionally,
math_engine.verify_math_expressionrunssimplify(actual - claimed)with no operation-level bound. Pathological inputs (simplifyon adversarial expressions is a known SymPy CPU sink) give each request up to 30s of free CPU burn inside the semaphore window.Why This Violates QWED Philosophy
Expected Behavior
Powwith integer base/exponent above a threshold (e.g., rejecta**bwhenb > 10_000anda > 1β the result would exceed ~33k bits).factorial(n)at a fixednceiling (e.g.,n <= 10_000).resource.setrlimit(RLIMIT_AS, ...)on POSIX; Job Objects on Windows) so a blowout kills the child, not the host.diff,integrate,simplify,solve) should run under an operation-level deadline so a single request cannot consume the entire tool-call window in CPU.Suggested Fix Direction
Note: bounds must be enforced on the parsed expression (post-
parse_expr), which meansparse_expritself must not eagerly evaluate β useevaluate=Falsewhere supported, or pre-scan operand magnitudes with a regex/AST pass before callingparse_expr. Whichever route is chosen, the invariant is: no eager evaluation of unbounded-magnitude operands.Environment
0.2.1src/qwed_mcp/engines/safe_parser.py,src/qwed_mcp/engines/math_engine.py,src/qwed_mcp/tools.py