Persistent Linux desktops for AI agents. Sleep, wake, or reboot: the identity stays on the volume. Drive over MCP or the local UI.
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
transport http counts 30 tools · 0 res
· 0 prompts
permission surface via code analysis
tools
-
auth_attempt_wait
-
case_skill
-
computer_action
-
computer_capture_read
-
computer_capture_start
-
computer_click_element
-
computer_create
-
computer_eval
-
computer_exec
-
computer_file_get
-
computer_file_put
-
computer_fill
-
computer_hover
-
computer_list
-
computer_login
-
computer_navigate
-
computer_screenshot
-
computer_sleep
-
computer_snapshot
-
computer_tabs
-
computer_upload
-
computer_wait_for
-
handoff_get
-
handoff_list
-
handoff_request
-
schedule_create
-
schedule_delete
-
schedule_list
-
schedule_run
-
schedule_runs
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit 611b7b5 · analyzer v33 · 1d ago
danger signals1
- over-broad OAuth scope https://mail.google.com/ case-computers-case-611b7b5/tests/test_links.py :120
for typed, want in [("https://mail.google.com/inbox", "mail.google.com"),
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 55
filesystem 12
- fs case-computers-case-611b7b5/control-plane/browse.py :349
im = Image.open(BytesIO(png)).convert("RGB") - fs case-computers-case-611b7b5/control-plane/cased.py :173
with open(os.path.join(AUDIT_DIR, time.strftime("%Y-%m-%d") + ".jsonl"), "a") as f: - fs case-computers-case-611b7b5/control-plane/config.py :22
with open("/proc/meminfo") as f: - fs case-computers-case-611b7b5/control-plane/scheduler.py :15
import shutil - fs case-computers-case-611b7b5/control-plane/store.py :96
fd = os.open(key_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) - fs case-computers-case-611b7b5/image/deskd.py :74
with open(FB, "rb") as f: - fs (weak) case-computers-case-611b7b5/tests/site_server.py :48
rec = json.load(open(RECORD)) if os.path.exists(RECORD) else [] - fs (weak) case-computers-case-611b7b5/tests/test_acceptance.py :105
with open(os.path.join(out, name), "wb") as f: - fs (weak) case-computers-case-611b7b5/tests/test_auth_attempts.py :6
import shutil - fs (weak) case-computers-case-611b7b5/tests/test_auth_wait.py :6
import shutil - fs (weak) case-computers-case-611b7b5/tests/test_browse.py :654
marked = Image.open(BytesIO(out)) - fs (weak) case-computers-case-611b7b5/tests/test_runs.py :47
open(inside, "wb").write(b"in")
shell / exec 3
- shell case-computers-case-611b7b5/control-plane/scheduler.py :16
import subprocess - shell case-computers-case-611b7b5/image/deskd.py :15
import subprocess - shell (weak) case-computers-case-611b7b5/tests/test_acceptance.py :18
import subprocess
network 14
- net case-computers-case-611b7b5/control-plane/assist.py :14
from urllib.parse import parse_qs, urlsplit - net case-computers-case-611b7b5/control-plane/auth_attempts.py :696
from urllib.parse import urlparse - net case-computers-case-611b7b5/control-plane/browse.py :31
from urllib.parse import quote - net case-computers-case-611b7b5/control-plane/captcha.py :26
import requests - net case-computers-case-611b7b5/control-plane/cased.py :19
from urllib.parse import parse_qs - net case-computers-case-611b7b5/control-plane/deskclient.py :14
import requests - net case-computers-case-611b7b5/control-plane/links.py :13
from urllib.parse import parse_qs, parse_qsl, urlencode, urlparse, urlsplit - net case-computers-case-611b7b5/control-plane/notify.py :17
import requests - net case-computers-case-611b7b5/image/deskd.py :20
from urllib.parse import urlparse - net case-computers-case-611b7b5/mcp/case_mcp.py :19
import requests - net (weak) case-computers-case-611b7b5/tests/site_server.py :13
from urllib.parse import parse_qs - net (weak) case-computers-case-611b7b5/tests/test_acceptance.py :23
import requests - net (weak) case-computers-case-611b7b5/tests/test_browse.py :7
from urllib.parse import quote - net (weak) case-computers-case-611b7b5/tests/test_captcha.py :127
with mock.patch("captcha.requests.post", return_value=upload) as post, \
secrets 9
- secrets case-computers-case-611b7b5/control-plane/captcha.py :344
if (os.environ.get("CASE_DBC_AUTHTOKEN") or "").strip(): - secrets case-computers-case-611b7b5/control-plane/cased.py :100
return (os.environ.get("CASE_TOKEN") or "").strip() - secrets case-computers-case-611b7b5/control-plane/notify.py :26
return (os.environ.get("CASE_NTFY_TOKEN") or "").strip() - secrets case-computers-case-611b7b5/control-plane/scheduler.py :85
if not BRAIN_CMD and not os.environ.get("ANTHROPIC_API_KEY"): - secrets case-computers-case-611b7b5/image/deskd.py :28
TOKEN = os.environ["DESK_TOKEN"] - secrets case-computers-case-611b7b5/mcp/case_mcp.py :46
tok = (os.environ.get("CASE_TOKEN") or "").strip() - secrets (weak) case-computers-case-611b7b5/tests/test_captcha.py :33
os.environ["CASE_DBC_PASSWORD"] = "p" - secrets (weak) case-computers-case-611b7b5/tests/test_notify.py :59
os.environ["CASE_NTFY_TOKEN"] = "secret-tok" - secrets (weak) case-computers-case-611b7b5/tests/test_token.py :20
os.environ["CASE_TOKEN"] = "share-me"
database 2
- db case-computers-case-611b7b5/control-plane/store.py :12
import sqlite3 - db (weak) case-computers-case-611b7b5/tests/test_dockerd.py :46
import sqlite3
tool registrations 30
- computer_create case-computers-case-611b7b5/mcp/case_mcp.py :61
- computer_list case-computers-case-611b7b5/mcp/case_mcp.py :71
- computer_screenshot case-computers-case-611b7b5/mcp/case_mcp.py :80
- computer_action case-computers-case-611b7b5/mcp/case_mcp.py :91
- computer_exec case-computers-case-611b7b5/mcp/case_mcp.py :121
- computer_eval case-computers-case-611b7b5/mcp/case_mcp.py :129
- computer_navigate case-computers-case-611b7b5/mcp/case_mcp.py :147
- computer_snapshot case-computers-case-611b7b5/mcp/case_mcp.py :163
- computer_click_element case-computers-case-611b7b5/mcp/case_mcp.py :183
- computer_hover case-computers-case-611b7b5/mcp/case_mcp.py :209
- computer_upload case-computers-case-611b7b5/mcp/case_mcp.py :220
- computer_fill case-computers-case-611b7b5/mcp/case_mcp.py :232
- computer_wait_for case-computers-case-611b7b5/mcp/case_mcp.py :251
- computer_tabs case-computers-case-611b7b5/mcp/case_mcp.py :277
- computer_capture_start case-computers-case-611b7b5/mcp/case_mcp.py :295
- computer_capture_read case-computers-case-611b7b5/mcp/case_mcp.py :307
- computer_login case-computers-case-611b7b5/mcp/case_mcp.py :319
- computer_file_put case-computers-case-611b7b5/mcp/case_mcp.py :356
- computer_file_get case-computers-case-611b7b5/mcp/case_mcp.py :363
- case_skill case-computers-case-611b7b5/mcp/case_mcp.py :408
- computer_sleep case-computers-case-611b7b5/mcp/case_mcp.py :479
- auth_attempt_wait case-computers-case-611b7b5/mcp/case_mcp.py :487
- handoff_request case-computers-case-611b7b5/mcp/case_mcp.py :555
- handoff_list case-computers-case-611b7b5/mcp/case_mcp.py :569
- handoff_get case-computers-case-611b7b5/mcp/case_mcp.py :581
- schedule_create case-computers-case-611b7b5/mcp/case_mcp.py :596
- schedule_list case-computers-case-611b7b5/mcp/case_mcp.py :607
- schedule_delete case-computers-case-611b7b5/mcp/case_mcp.py :613
- schedule_run case-computers-case-611b7b5/mcp/case_mcp.py :620
- schedule_runs case-computers-case-611b7b5/mcp/case_mcp.py :626
declared dependencies 7
- mcp@==1.28.1
- fastapi@==0.139.0
- uvicorn@==0.50.2
- docker@==7.1.0
- cryptography@==49.0.0
- requests@==2.34.2
- Pillow@==12.2.0
perm:untrusted 2
- untrusted case-computers-case-611b7b5/image/deskd.py :230
pages = [t for t in requests.get(f"{CDP}/json/list", timeout=5).json() if t["type"] == "page"] - untrusted (weak) case-computers-case-611b7b5/tests/test_acceptance.py :284
assert "name=secret type=password" in requests.get(f"{ROOT}/fill/{tok}", timeout=10).text
transport_posture 1
- binds all interfaces (0.0.0.0) case-computers-case-611b7b5/image/deskd.py :1024
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="warning", access_log=False)