diff --git a/packages/code-runtime/code-runtime-python/py/bootstrap.py b/packages/code-runtime/code-runtime-python/py/bootstrap.py index df0a4bb42b..93638a50fb 100644 --- a/packages/code-runtime/code-runtime-python/py/bootstrap.py +++ b/packages/code-runtime/code-runtime-python/py/bootstrap.py @@ -753,6 +753,10 @@ async def _run(channel: ProtocolChannel) -> None: # assignment RHS resolves the module global, not an unbound local. _RuntimeError_cls = RuntimeError _BindingRejection_cls = _BindingRejection + # `str` for dispatch's rejection conversion is likewise bound: a program + # rebinding `__main__.str` would otherwise run a hostile callable when the + # binding-rejection message is formatted. + _str = str # 1. Boot handshake. boot = channel.read_frame() if boot is None or boot.get("type") != "boot": @@ -917,7 +921,7 @@ async def _run(channel: ProtocolChannel) -> None: try: return await fut except _BindingRejection_cls as exc: - raise call_failure(str(exc)) from None + raise call_failure(_str(exc)) from None namespaces: dict[str, Any] = {} for entry in boot["namespaces"]: diff --git a/packages/code-runtime/code-runtime-python/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-python/tests/runtime.spec.ts index 692ed9d51b..c4c3f3e934 100644 --- a/packages/code-runtime/code-runtime-python/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-python/tests/runtime.spec.ts @@ -690,7 +690,7 @@ describe('PythonCodeRuntime — programs and bindings', () => { 'try:', ' await tools.fail({})', 'except RuntimeError as e:', - ' caught = str(e)', + ' caught = e.args[0] if e.args else ""', 'except Exception as e:', ' caught = "WRONG TYPE: " + type(e).__name__', 'return caught',