unsloth/studio
danielhanchen 236e89d0c9 Harden sandbox: workdir-vetter alias / namespace / MRO / sys.modules gaps, network client entry points, request() URL arg, sqlite URI mode parsing
Close eight gaps Codex found on the round-60 branch (seven inline P1 plus one
review-body P1). Five are in the runtime workdir-module import vetter (a planted
workdir helper is not scanned by the outer static pass), two are in the static
network scanner, and one is the runtime sqlite URI parser.

- assigned os aliases in the vetter: the pre-pass only recorded `import os as o`
  aliases, so a workdir helper doing `import os; o = os; o.system(...)` passed
  vetting and spawned an unguarded child. Follow simple whole-module assignments
  (o = os; b = builtins; s = sys) to a fixpoint before the sink checks.

- module namespace-dict subscripts in the vetter: `os.__dict__['system'](...)`
  reached the sink because __dict__ was not a gadget and the subscript branch only
  failed closed for builtins. Fail closed on a `<module>.__dict__[...]` subscript
  for os / posix / deserializer / sys / importlib, like vars(<module>).

- module __getattribute__ / __getattr__ in the vetter: `os.__getattribute__(
  'system')(...)` reached the sink because only the builtin getattr(...) form was
  recognized. Classify bound `module.__getattribute__('name')` and unbound
  `object.__getattribute__(module, 'name')` lookups the same way as getattr.

- MRO base recovery in the vetter: `io.FileIO.__mro__[1]('/tmp/x','w')` /
  `sqlite3.Connection.__mro__[1](...)` recovered an unguarded base class because the
  helper gadget set omitted __mro__ / mro. Add both to the gadget attributes.

- sys.modules in the vetter: `sys.modules['os'].system(...)` recovered the
  guard-cached os module without an import, bypassing the denied-import path. Deny
  sys.modules access (direct attribute and getattr form) in a vetted workdir module.

- public network client entry points: `requests.api.get(...)`, `ftplib.FTP(...)`,
  and `smtplib.SMTP(...)` were not in the network prefix table, so a metadata /
  untrusted host reached through them bypassed the allowlist. Add requests.api.*,
  ftplib.FTP / FTP_TLS, and smtplib.SMTP / SMTP_SSL / LMTP (the ftplib / smtplib
  clients take a bare host), and track ftplib / smtplib import aliases.

- request(method, url) URL argument: module-level requests.request / httpx.request /
  urllib3.request (and requests.api.request) carry the URL at arg1, but the code
  passed arg0 (the HTTP method) to the host check, so the URL was never inspected.
  Read the URL from arg1 for these method-first APIs, like the client-instance
  .request() branch.

- sqlite URI mode=memory parsing: a `file:/tmp/escape.db?xmode=memory` URI was
  treated as in-memory by a substring test and skipped path confinement, but SQLite
  ignores the unknown xmode key and opens the on-disk file. Parse the query exactly
  (split on &, first occurrence of a repeated key, percent-decoded) and treat only a
  genuine mode=memory parameter as in-memory, in the runtime guard and the two static
  sqlite operand checks.

Regression coverage: TestRound61Bypasses in tests/test_sandbox_tools.py (request()
URL at arg1 for requests / httpx / urllib3 / requests.api, network client entry
points against metadata and untrusted hosts, sqlite shell xmode=memory on an
escaping absolute path, plus a benign-allowed set: trusted-host requests / api /
ftplib / smtplib, a genuine in-memory URI, and a workdir-relative db) and, in
tests/test_sandbox_runtime_backstop.py, workdir-module denials for the assigned os
alias, os.__dict__ subscript, os.__getattribute__, io.FileIO.__mro__, and
sys.modules['os'] forms, a benign os-alias helper that still imports, and the sqlite
URI xmode=memory escape denial plus a genuine mode=memory allowance.
2026-07-11 05:29:35 +00:00
..
backend Harden sandbox: workdir-vetter alias / namespace / MRO / sys.modules gaps, network client entry points, request() URL arg, sqlite URI mode parsing 2026-07-11 05:29:35 +00:00
frontend Stabilize floating monitor drag (#6984) 2026-07-09 00:16:05 -07:00
src-tauri Speed up Studio startup path (#6899) 2026-07-07 18:08:07 -07:00
__init__.py Final cleanup 2026-03-12 18:28:04 +00:00
install_llama_prebuilt.py Studio: add Vulkan llama.cpp support (#5819) 2026-07-09 03:39:48 -07:00
install_node_prebuilt.py Pin isolated Node.js installer to committed sha256 digests (#6625) 2026-06-24 05:47:58 -07:00
install_python_stack.py Studio: fix flash-attn and torchao install on Blackwell (sm_100+) GPUs (Closes #6961) (#6970) 2026-07-08 06:38:10 -07:00
LICENSE.AGPL-3.0 Add AGPL-3.0 license to studio folder 2026-03-09 19:36:25 +00:00
node_prebuilt_pins.json Pin isolated Node.js installer to committed sha256 digests (#6625) 2026-06-24 05:47:58 -07:00
package-lock.json ci: advisory lockfile supply-chain audit (no install-script changes) (#5604) 2026-05-19 05:56:56 -07:00
package.json ci: advisory lockfile supply-chain audit (no install-script changes) (#5604) 2026-05-19 05:56:56 -07:00
setup.bat Final cleanup 2026-03-12 18:28:04 +00:00
setup.ps1 Fix Windows installer torch index override (#6972) 2026-07-09 03:46:47 -07:00
setup.sh Studio: source CPU llama.cpp prebuilts from unslothai/llama.cpp (#6311) 2026-07-08 05:34:59 -07:00
Unsloth_Studio_Colab.ipynb Studio Colab: opt-in shareable Cloudflare tunnel link (#6684) 2026-06-26 00:56:23 -07:00