Skip to content

feat(task-steps): native OSWorld initialize and evaluate on computer envs (FD-5492) - #606

Open
williamloo-scale wants to merge 3 commits into
mainfrom
wloo/osworld-native-computer-steps
Open

williamloo-scale wants to merge 3 commits into
mainfrom
wloo/osworld-native-computer-steps

Conversation

@williamloo-scale

@williamloo-scale williamloo-scale commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds three task steps to core: osworld_deploy_controller, osworld_initialize and osworld_evaluate. It also adds the osworld-server computer app (agent_env.osworld). Together they let an OSWorld task run on a framework computer env. Both task kinds are supported:

  • Classic: init_config plus evaluator.
  • OSWorld-V2: a task_NNN.py that defines TASK_CLASS.

No plugin is needed.

Design

The controller runs as a separate sidecar.

  • The OSWorld controller holds the grader, the task's checks and the judge's model key.
  • A computer's apps run as its session user, and the agent runs as that user too.
  • So the controller runs in a container sandbox of its own, beside the computer, in remote mode. The agent can't read it.

The computer runs only the OSWorld guest server, as the osworld-server app.

  • The app's own server forwards /osworld/<route> to 127.0.0.1:5000.
  • Calls need the env's control token, which the app removes before forwarding.

The guest server is found through the computer's card.

  • The app's card advertises the extension urn:agentenv:osworld-guest/v1 at its forward prefix. A GET on that endpoint reports whether the guest server is up.
  • The computer roots the endpoint wherever it serves the app. So osworld_deploy_controller finds the guest server by the extension's URI in the computer's card, and no /svc/<name> route is built anywhere.
  • It reads the stored card first. If the app's server wasn't answering yet when that card was read, it reads the live card again for up to 2 minutes.
  • A computer without the app fails before a sandbox is created.

Step reference

osworld_deploy_controller

  • Fields: env_id, controller_image_artifact_id (a docker_image artifact; default cua-controller), ttl_seconds, cpu, memory_mb, env_vars.
  • Controller env vars: PROVIDER=remote, OS_TYPE=Ubuntu, REMOTE_VM_IP=<guest URL from the card>, and REMOTE_SERVER_HEADERS=<JSON of DeployedEnv.control_headers>. It also passes LITELLM_API_KEY and LITELLM_BASE_URL from [model] when they're configured.
    • env_vars go first, so the step's own values win.
    • Only the variable names are logged.
  • Waits until GET /configure answers (the controller has no health route).
  • Records on the env (DeployedEnv.metadata): osworld_controller_url, osworld_controller_sandbox_id and osworld_guest_url.
  • Teardown: the sandbox goes into context.deployed_sandboxes as osworld-controller-<env_id>.

osworld_initialize

  • Fields: env_id, init_config, osworld_v2_task_path, and the legacy osworld_v2_task_url (the path wins if both are set).
  • OSWorld-V2: POST /reset, then POST /initialize_task {id, osworld_v2_task_url}. It fails on success: false or a truthy error.
  • Classic: sends the whole init_config to POST /setup, which serves every setup type. It fails on success: false or on any seeded site with ok: false. Seeded sites are recorded in context.metadata["osworld_seeded_sites"].

osworld_evaluate

  • Fields: env_id, evaluator, verifier_id (default: a uuid hex), osworld_v2_task_path / osworld_v2_task_url, and judge_model.
  • OSWorld-V2: /evaluate {osworld_v2_task_url}.
  • Classic: every func is sent to the controller's /evaluate, one at a time, with its result and expected getters and its options. Results are combined by conj. No grading runs in the worker.
    • infeasible is the one exception: it is graded on the agent's answer (the [INFEASIBLE] tag), as cua_evaluate does.
    • The judge funcs get rubric and parameters, plus model=judge_model when the func's options set none. Deterministic funcs have any model option removed.
  • Transport: /evaluate_async, then polling /evaluate_result. A controller without those routes (404) gets the blocking /evaluate.
  • Re-grades: stage_files (from step_overrides) is downloaded through /setup before anything reads the computer. The step refuses to grade if staging fails.
  • postconfig: runs once through /setup before grading. A failure is logged and grading continues.
  • Skips: a turn whose error_type is set is recorded as a skip with score 0. On classic tasks, an agent that ran out of turns or time is graded anyway and marked partial_credit (on the verification and in context.metadata["partial_credit"][verifier_id]).
  • Controller errors score 0 instead of failing the step.
  • Task refs: an http(s) URL is passed through. An object-store ref is signed for 6 hours, but only if it's in the object store and under <prefix>artifacts/; anything else is refused.

Result shape (same as cua_evaluate)

context.metadata["verifications"][verifier_id] = {"results": [...], "score": float}

  • V2: results=[{"id": "osworld_v2", "score", "result": not error, "message"}].
  • Classic: results=[{"func", "results": [{"id", "score", "result", "message"}]}], plus debug (overall_score, conjunction, metrics, error, message) and partial_credit when it applies.

Staging the app

python -m agent_env.osworld stage --source <OSWorld guest server source: main.py, pyxcursor.py> --out ./osworld-server
agent-env env put ./osworld-server

The guest server's source isn't vendored; it's staged under payload/. The app's declaration passes the checks a put runs. Then add the app to the computer env's apps.

Dependencies

Known gaps

  • Formerly local funcs are now graded by the controller's OSWorld implementations, so scores may differ slightly from cua_evaluate's for the same task. These funcs are: compare_docx_files, compare_docx_tables, compare_pptx_files, compare_table, check_json_settings, check_json_keybindings, is_extension_installed, check_include_exclude, file_contains, run_sqlite3, check_thunderbird_prefs and check_thunderbird_filter.
    • Every one exists in the controller's metrics, and every getter type cua_evaluate reads (vm_file, cloud_file, rule, vm_command_line, the vscode getters) exists in its getters. So nothing becomes unservable.
  • The opencode judge's transcript isn't collected. It stays on the controller's sandbox.
  • Chrome DevTools getters (:9222), VLC (:8080) and the controller's WebSocket streams aren't reachable through the app. Only the guest server's HTTP routes are forwarded.
  • The accessibility tree relies on the OS's python3-pyatspi, which reaches the app's venv through sys.path. This needs checking on a live computer.
  • Setups that need root: the guest server runs as the session user.
  • App parity: the desktop apps OSWorld tasks expect (LibreOffice, GIMP, VLC, Thunderbird, VS Code) aren't in ubuntu-24.04.
  • Platform: Linux and X11 only.
  • Nothing has run end to end on a live computer env yet. Every test below is a unit test.

Testing

  • New tests: 50 unit tests in tst/unit/osworld/ (guest resolution, controller transport, the three steps, the app).
    • Guest resolution: from the stored card, the live card read again, a computer missing the app, an env with no address.
    • Controller transport: HTTP errors with their status, non-JSON answers, /evaluate_async polling through transient errors, the 404 fallback, failed jobs, score normalization, and signing refused outside the artifacts.
    • osworld_deploy_controller: env vars, metadata, the sandbox record, no secrets in the logs, refusal before any sandbox is created, and no double deploy.
    • osworld_initialize: V2 and classic, including site failures.
    • osworld_evaluate: V2, a V2 controller error scoring 0, the error_type skip for V2 and classic, conj and/or across funcs, a single func's partial score, a failing func among others, infeasible, partial credit, postconfig running once, and stage_files.
    • The app: the card extension, the forward (control token removed), 502 when the guest server is down, and staging.
  • Lint: ruff check passes.
  • Full unit suite (tst/unit and packages/agentenv-protocol/tests): 14402 passed, 67 skipped, 3 failed. The 3 failures are test_disk_recipe (Windows ISO boot) and test_docker_image_github_clone (two cases of the token-signs-the-clone test); they fail the same way on main.

Docs

The site should cover:

  • the three steps and their fields;
  • the osworld-server app and the urn:agentenv:osworld-guest/v1 extension;
  • staging the guest server's source;
  • the controller image (controller_image_artifact_id).

End-to-end test

tst/integration/computer/osworld_test.py runs on local Docker: a new computer env (osworld-desk: ubuntu-24.04, the reference driver, the osworld-server app), the controller built from scale-cua #360 beside it, a classic init_config execute set up through the controller, then check_include_exclude over vm_command_line graded by the controller. A rule that matches scores 1.0 and one that doesn't scores 0.0. It passes (2 m 33 s). It needs OSWORLD_SERVER_SOURCE and OSWORLD_CONTROLLER_IMAGE and skips without them.

The first live run found four bugs, fixed in 460b019: the controller got a loopback address its container can't reach, the guest server's service command wasn't found, python-xlib needed an ~/.Xauthority, and screenshots needed scrot. The controller's address is also now saved in the run's context metadata, since a deployed env's record isn't re-saved after deploy.

Not covered yet: an agent, an OSWorld-V2 .py task, LLM-judge funcs, a cloud sandbox provider.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 2/5

Do not merge until the controller is protected from agent access, fallback URLs are corrected, and the repository requirements are satisfied.

Fix All in CursorFindings

  1. P1 Security Agent can reach the grader ▶
  2. P1 Fallback keeps the wrong address ▶
  3. P2 Checks disappear from grades ▶
  4. P2 Setup responses enter logs ▶
  5. P2 Disk setting lacks a name ▶
Fix with agent prompt
### Issue 1
src/agent_env/task_step/task_steps/osworld/deploy_controller.py:102-104
On local Linux Docker, `create_container` publishes the controller's port on the Docker bridge gateway. A computer without a network restriction can reach that address. The controller accepts calls without authentication, so the agent can call `/reset`, `/setup`, or `/evaluate` directly and interfere with task state or grading. A separate container does not block this access.

Require a controller-only credential or put its listener behind a boundary the computer cannot reach.

**How this was verified:** The local provider publishes the controller port on the bridge gateway, the computer defaults to unrestricted networking, and the worker calls the controller routes without credentials.

### Issue 2
src/agent_env/task_step/task_steps/osworld/deploy_controller.py:97-99
`provider` can still be a `ChainedSandboxProvider`, even when filtering leaves only one local link. That class inherits `url_from_sandbox`, which returns the URL unchanged. If the chain selects local Docker, a guest URL such as `http://127.0.0.1:...` points inside the controller instead of at the computer. A local `LITELLM_BASE_URL` fails the same way.

Build these values for the concrete provider being tried, not for the chain.

### Issue 3
src/agent_env/task_step/task_steps/osworld/evaluate.py:162-164
`zip` silently drops trailing functions when a nonempty `result`, `expected`, or `options` list is shorter than `funcs`. For example, two functions with `options: [{}]` run only the first check and can record a passing score without checking the second.

Check list lengths and reject mismatches, or explicitly fill missing optional entries. This would keep task authors from accidentally leaving checks out of a grade.

### Issue 4
src/agent_env/task_step/task_steps/osworld/evaluate.py:125
When `success` is false and `error` is absent, `run_setup` puts the whole controller response into its exception. This warning then logs that response unchanged.

That violates the repository directive, “Never log full response bodies, request bodies, or large serialized objects in production code.” Log the failure type and a bounded summary instead. This repository requirement must be satisfied before merging.

### Issue 5
src/agent_env/task_step/task_steps/osworld/deploy_controller.py:103
`disk_size_gb=10` adds an unnamed controller resource setting. The repository requires magic numbers to be stored as class or instance variables with descriptive names. Give this disk size a named class setting so its purpose is clear and it can be changed in one place. This repository requirement must be satisfied before merging.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds native OSWorld setup and grading on computer environments.

  • OSWorld tasks find the computer app and run their controller beside it.
  • OSWorld tasks can set up classic and V2 task state on a computer.
  • OSWorld tasks record classic and V2 grading results on the computer run.

Acknowledged scope:

  • williamloo-scale explicitly documents V2 budget-exhaustion skips as intentional; only classic tasks receive partial-credit grading.
  • williamloo-scale acknowledges missing desktop apps, inaccessible auxiliary ports, root-dependent setups, and judge transcript collection as known gaps.

Diagram

sequenceDiagram
    participant Worker
    participant Controller
    participant Computer
    participant Guest
    Worker->>Computer: Read guest endpoint from card
    Worker->>Controller: Deploy with guest URL and control headers
    Worker->>Controller: Initialize or evaluate task
    Controller->>Computer: Guest request with control token
    Computer->>Guest: Forward request without token
    Guest-->>Controller: Task state or result
    Controller-->>Worker: Grade
    Note over Computer,Controller: Local Docker also lets computer code reach the controller port
Loading

Reviews (1) · Last reviewed commit: "test(osworld): the end-to-end test skips..." · Reviewed by Greptile

…envs

Adds the osworld_deploy_controller, osworld_initialize and osworld_evaluate
steps and the osworld-server computer app (agent_env.osworld), so an OSWorld
task (classic init_config/evaluator or an OSWorld-V2 task_NNN.py) runs on a
framework computer env.

- The OSWorld controller runs in a container sandbox of its own beside the
  computer, in remote mode, so the grader, a task's checks and the judge's
  key stay out of the agent's reach (a computer's apps run as its session
  user).
- The computer runs only the OSWorld guest server, as the osworld-server
  app. Its card advertises urn:agentenv:osworld-guest/v1 at the prefix the
  app forwards to the guest server; the deploy step resolves the guest
  server's address from the computer's card (stored, else live until the
  app answers) and refuses a computer without the app before creating a
  sandbox.
- osworld_initialize: OSWorld-V2 via /reset + /initialize_task; classic via
  /setup with the whole init_config.
- osworld_evaluate: OSWorld-V2 via /evaluate; classic sends every func to
  the controller's /evaluate (async-polled, blocking fallback) and combines
  by conj; verifications shape matches cua_evaluate's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@socket-security

socket-security Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​pillow@​10.1.0802510010080
Addedpypi/​python3-xlib@​0.15991001007570
Addedpypi/​lxml@​6.1.39810010010080
Addedpypi/​pyautogui@​0.9.54100100100100100

View full report

@socket-security

socket-security Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Critical priority
Critical CVE: Arbitrary Code Execution in Pillow

CVE: GHSA-3f63-hfp8-52jq Arbitrary Code Execution in Pillow (CRITICAL)

Affected versions: < 10.2.0

Patched version: 10.2.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a critical CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: Out-of-bounds read via attacker-controlled row stride on Pillow's mmap path (McIdas AREA files)

CVE: GHSA-62p4-gmf7-7g93 Pillow: Out-of-bounds read via attacker-controlled row stride on Pillow's mmap path (McIdas AREA files) (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: Heap out-of-bounds write Image.paste() / `Image.crop()` via signed coordinate overflow

CVE: GHSA-6r8x-57c9-28j4 Pillow: Heap out-of-bounds write Image.paste() / Image.crop() via signed coordinate overflow (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow JPEG2000 tiled decode retains a growing scratch buffer and can be used for denial of service

CVE: GHSA-vjc4-5qp5-m44j Pillow JPEG2000 tiled decode retains a growing scratch buffer and can be used for denial of service (HIGH)

Affected versions: >= 8.2.0 < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow PcfFontFile._load_bitmaps(): `Image.frombytes()` called without `_decompression_bomb_check()` — bomb protection bypass via PCF font loading

CVE: GHSA-8v84-f9pq-wr9x Pillow PcfFontFile._load_bitmaps(): Image.frombytes() called without _decompression_bomb_check() — bomb protection bypass via PCF font loading (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: Heap out-of-bounds write in ImageFilter.RankFilter via integer overflow in `ImagingExpand`

CVE: GHSA-xj96-63gp-2gmr Pillow: Heap out-of-bounds write in ImageFilter.RankFilter via integer overflow in ImagingExpand (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: Controlled heap out-of-bounds write in Pillow ImageCmsTransform.apply() via output mode mismatch

CVE: GHSA-9hw9-ch79-4vh6 Pillow: Controlled heap out-of-bounds write in Pillow ImageCmsTransform.apply() via output mode mismatch (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: Decompression Bomb DoS via PdfParser.PdfStream.decode()

CVE: GHSA-jjj6-mw9f-p565 Pillow: Decompression Bomb DoS via PdfParser.PdfStream.decode() (HIGH)

Affected versions: >= 5.1.0 < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow BdfFontFile: `Image.new()` called without `_decompression_bomb_check()` — bomb protection bypass via font loading

CVE: GHSA-45hq-cxwh-f6vc Pillow BdfFontFile: Image.new() called without _decompression_bomb_check() — bomb protection bypass via font loading (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow: FontFile.compile(): `Image.new()` called without `_decompression_bomb_check()`

CVE: GHSA-5x94-69rx-g8h2 Pillow: FontFile.compile(): Image.new() called without _decompression_bomb_check() (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow GdImageFile._open(): image dimensions accepted without `_decompression_bomb_check()`

CVE: GHSA-phj9-mv4w-65pm Pillow GdImageFile._open(): image dimensions accepted without _decompression_bomb_check() (HIGH)

Affected versions: < 12.3.0

Patched version: 12.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: Pillow buffer overflow vulnerability

CVE: GHSA-44wm-f244-xhp3 Pillow buffer overflow vulnerability (HIGH)

Affected versions: < 10.3.0

Patched version: 10.3.0

From: src/agent_env/osworld/apps/osworld-server/requirements.txt → pypi/pillow@10.1.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/pillow@10.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn

View full report

@williamloo-scale williamloo-scale changed the title feat(task-steps): native OSWorld initialize and evaluate on computer envs feat(task-steps): native OSWorld initialize and evaluate on computer envs (FD-5492) Nov 11, 2026
williamloo-scale and others added 2 commits November 11, 2026 23:35
…tion test (FD-5492)

A computer env with the osworld-server app, the controller beside it, a classic task set up and graded
through it: pass scores 1.0, fail 0.0. Running it found:

- The controller got the guest server's address as this process reaches it; a local container reaches
  this machine's loopback by another name. It now gets it, and the model endpoint, through
  url_from_sandbox, as an agent's deploy does.
- supervisord looks a bare command up on PATH, so the guest server's service never started: it runs
  as `bash start-osworld-server.sh`.
- python-xlib refuses to connect without an Xauthority file; the start script makes an empty one.
- pyautogui's screenshots need scrot on X11; the app installs it.
- A deployed env's record is stored once, when it is deployed, so the controller's address written on
  it lasted only the process. It is recorded in the run's context metadata too, and read from there.

tst/integration/computer/osworld_test.py stages the app from OSWORLD_SERVER_SOURCE and runs the controller
image OSWORLD_CONTROLLER_IMAGE (one with scale-cua #360); it skips without them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ility (FD-5492)

It needs scale-cua's guest server source and a controller image, which this repository doesn't carry,
so it skips without them. CI's skip policy fails a skip that isn't a declared capability gap, so the
skip names osworld_sources, the slow tier allows it as it does mcp_server_sources, and CONTRIBUTING
asks a change to the OSWorld code to run the test with both set and say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@williamloo-scale
williamloo-scale marked this pull request as ready for review November 12, 2026 19:57
@williamloo-scale
williamloo-scale requested a review from a team as a code owner November 12, 2026 19:57
Comment on lines +102 to +104
sandbox = await provider.create_container(image_name=image.pinned_name, port=CONTROLLER_PORT, env=env,
cpu=self.cpu, memory=self.memory_mb, disk_size_gb=10,
timeout=self.ttl_seconds, attribution=deploy_attribution(self, context))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Agent can reach the grader

On local Linux Docker, create_container publishes the controller's port on the Docker bridge gateway. A computer without a network restriction can reach that address. The controller accepts calls without authentication, so the agent can call /reset, /setup, or /evaluate directly and interfere with task state or grading. A separate container does not block this access.

Require a controller-only credential or put its listener behind a boundary the computer cannot reach.

How this was verified: The local provider publishes the controller port on the bridge gateway, the computer defaults to unrestricted networking, and the worker calls the controller routes without credentials.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/osworld/deploy_controller.py
Line: 102-104

Comment:
**Agent can reach the grader**

On local Linux Docker, `create_container` publishes the controller's port on the Docker bridge gateway. A computer without a network restriction can reach that address. The controller accepts calls without authentication, so the agent can call `/reset`, `/setup`, or `/evaluate` directly and interfere with task state or grading. A separate container does not block this access.

Require a controller-only credential or put its listener behind a boundary the computer cannot reach.

**How this was verified:** The local provider publishes the controller port on the bridge gateway, the computer defaults to unrestricted networking, and the worker calls the controller routes without credentials.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +97 to +99
env = self.controller_env(deployed, provider.url_from_sandbox(guest_url))
if "LITELLM_BASE_URL" in env:
env["LITELLM_BASE_URL"] = provider.url_from_sandbox(env["LITELLM_BASE_URL"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Fallback keeps the wrong address

provider can still be a ChainedSandboxProvider, even when filtering leaves only one local link. That class inherits url_from_sandbox, which returns the URL unchanged. If the chain selects local Docker, a guest URL such as http://127.0.0.1:... points inside the controller instead of at the computer. A local LITELLM_BASE_URL fails the same way.

Build these values for the concrete provider being tried, not for the chain.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/osworld/deploy_controller.py
Line: 97-99

Comment:
**Fallback keeps the wrong address**

`provider` can still be a `ChainedSandboxProvider`, even when filtering leaves only one local link. That class inherits `url_from_sandbox`, which returns the URL unchanged. If the chain selects local Docker, a guest URL such as `http://127.0.0.1:...` points inside the controller instead of at the computer. A local `LITELLM_BASE_URL` fails the same way.

Build these values for the concrete provider being tried, not for the chain.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +162 to +164
n = len(funcs)
return list(zip(funcs, self.evaluator.get("result") or [None] * n, self.evaluator.get("expected") or [None] * n,
[o or {} for o in self.evaluator.get("options") or [{}] * n]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Checks disappear from grades

zip silently drops trailing functions when a nonempty result, expected, or options list is shorter than funcs. For example, two functions with options: [{}] run only the first check and can record a passing score without checking the second.

Check list lengths and reject mismatches, or explicitly fill missing optional entries. This would keep task authors from accidentally leaving checks out of a grade.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/osworld/evaluate.py
Line: 162-164

Comment:
**Checks disappear from grades**

`zip` silently drops trailing functions when a nonempty `result`, `expected`, or `options` list is shorter than `funcs`. For example, two functions with `options: [{}]` run only the first check and can record a passing score without checking the second.

Check list lengths and reject mismatches, or explicitly fill missing optional entries. This would keep task authors from accidentally leaving checks out of a grade.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

try:
await run_setup(url, postconfig, what=f"osworld_evaluate '{self.verifier_id}' postconfig")
except Exception as e:
logger.warning(f"osworld_evaluate '{self.verifier_id}': postconfig failed, grading anyway: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Setup responses enter logs

When success is false and error is absent, run_setup puts the whole controller response into its exception. This warning then logs that response unchanged.

That violates the repository directive, “Never log full response bodies, request bodies, or large serialized objects in production code.” Log the failure type and a bounded summary instead. This repository requirement must be satisfied before merging.

Rule Used: What: Never log full response bodies, request bodies, or large serialized objects in production code. Why: Large logs are expensive, noisy, hard to search, risk pipeline limits, and can leak sensitive data. Good: ``` logger.info('Search completed',... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/osworld/evaluate.py
Line: 125

Comment:
**Setup responses enter logs**

When `success` is false and `error` is absent, `run_setup` puts the whole controller response into its exception. This warning then logs that response unchanged.

That violates the repository directive, “Never log full response bodies, request bodies, or large serialized objects in production code.” Log the failure type and a bounded summary instead. This repository requirement must be satisfied before merging.

**Rule Used:** What: Never log full response bodies, request bodies, or large serialized objects in production code.  Why: Large logs are expensive, noisy, hard to search, risk pipeline limits, and can leak sensitive data.  Good: ``` logger.info('Search completed',... ([source](https://app.greptile.com/-/switch-tenant?tenant=scale-ai&next=%2Fcustom-context%3Fmemory%3Dfa8d684f-4686-4f3e-b1ef-c27453f614ea))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

logger.info(f"Deploying the OSWorld controller for env '{self.env_id}' (image={image.id} v{image.version}, "
f"env={sorted(env)})")
sandbox = await provider.create_container(image_name=image.pinned_name, port=CONTROLLER_PORT, env=env,
cpu=self.cpu, memory=self.memory_mb, disk_size_gb=10,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Disk setting lacks a name

disk_size_gb=10 adds an unnamed controller resource setting. The repository requires magic numbers to be stored as class or instance variables with descriptive names. Give this disk size a named class setting so its purpose is clear and it can be changed in one place. This repository requirement must be satisfied before merging.

Rule Used: Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. (source)

Learned From
scaleapi/scaleapi#126388

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/osworld/deploy_controller.py
Line: 103

Comment:
**Disk setting lacks a name**

`disk_size_gb=10` adds an unnamed controller resource setting. The repository requires magic numbers to be stored as class or instance variables with descriptive names. Give this disk size a named class setting so its purpose is clear and it can be changed in one place. This repository requirement must be satisfied before merging.

**Rule Used:** Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. ([source](https://app.greptile.com/-/switch-tenant?tenant=scale-ai&next=%2Fcustom-context%3Fmemory%3D002e0051-41ad-46c1-9098-47433c580150))

**Learned From**
[scaleapi/scaleapi#126388](https://github.com/scaleapi/scaleapi/pull/126388)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Cursor Fix in Claude Code Fix in Codex

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant