From eed25b3845ed1b6a0cb8cc3698ecc07f5553b88e Mon Sep 17 00:00:00 2001
From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com>
Date: Thu, 16 Jul 2026 06:22:16 -0700
Subject: [PATCH] Harden auto permission network gates
---
studio/backend/core/inference/tools.py | 45 +++++++++++++++++---
studio/backend/tests/test_permission_mode.py | 16 +++++++
studio/backend/tests/test_sandbox_tools.py | 13 ++++++
3 files changed, 67 insertions(+), 7 deletions(-)
diff --git a/studio/backend/core/inference/tools.py b/studio/backend/core/inference/tools.py
index dd268a6bb7..29feaf40b0 100644
--- a/studio/backend/core/inference/tools.py
+++ b/studio/backend/core/inference/tools.py
@@ -552,6 +552,10 @@ _AUTO_SENSITIVE_MCP_NOUN_RE = re.compile(
re.IGNORECASE,
)
+# Low-level clients bypass the sandbox host scanner, so sandboxed Python blocks
+# them and auto mode asks before they can run.
+_SANDBOX_BLOCKED_NETWORK_MODULES = frozenset({"httpcore", "boto3", "botocore"})
+
# Python: modules whose import alone signals side effects auto mode should ask
# about (process spawning, network, bulk file ops, low-level memory).
_AUTO_UNSAFE_PY_MODULES = frozenset(
@@ -605,6 +609,7 @@ _AUTO_UNSAFE_PY_MODULES = frozenset(
"venv",
}
)
+_AUTO_UNSAFE_PY_MODULES |= _SANDBOX_BLOCKED_NETWORK_MODULES
# Attribute calls that mutate the filesystem / spawn processes (os.remove,
# Path.write_text, sock.connect, ...) regardless of how the module was bound.
_AUTO_UNSAFE_PY_ATTRS = frozenset(
@@ -2403,19 +2408,22 @@ _RENDER_HTML_NETWORK_RE = re.compile(
r"@import|"
r"url\(\s*[\"']?\s*(?:https?:|/)|"
r"") is True
assert rh("") is True
@@ -995,6 +1002,15 @@ def test_render_html_gated_only_when_networked():
# Obfuscated egress: a block comment splitting fetch(, or bracket access.
assert rh("") is True
assert rh("") is True
+ assert rh("") is True
+ assert rh("") is True
+ assert (
+ rh(
+ ""
+ )
+ is True
+ )
# A computed bracket key spliced from string fragments on a global host object.
assert rh("") is True
assert rh("") is True
diff --git a/studio/backend/tests/test_sandbox_tools.py b/studio/backend/tests/test_sandbox_tools.py
index 2970b1a6bb..2341bef108 100644
--- a/studio/backend/tests/test_sandbox_tools.py
+++ b/studio/backend/tests/test_sandbox_tools.py
@@ -121,6 +121,19 @@ class TestUntrustedHostBlock:
_ok('import requests; url = "https://example.com/"; requests.get(url)')
+class TestLowLevelNetworkModules:
+ @pytest.mark.parametrize(
+ "code",
+ [
+ 'import httpcore; httpcore.request("GET", "https://example.com")',
+ 'import boto3; boto3.client("s3").list_buckets()',
+ "from botocore.session import get_session; get_session()",
+ ],
+ )
+ def test_low_level_client_blocked(self, code):
+ _blocked(code, expect_phrase = "Blocked: low-level network module")
+
+
class TestHostNormalization:
def test_trailing_dot_treated_same(self):
_ok('import requests; requests.get("https://wikipedia.org./")')