OpenHands / OpenHands/software-agent-sdk

OpenHands Fork Audit - HIGH: get_litellm_model_info makes unvalidated httpx.get call at LLM init

Open
#4,263 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-triage
Dominant language
Python
Stars
1.1k
Forks
539
Avg merge
1d 19h
Merged PRs (30d)
137

Description

FLEET AUDIT FINDING: OpenHands Zentra fork — egress completeness audit

Location: vendor/openhands-sdk/openhands/sdk/llm/utils/model_info.py:31, called from llm.py:2229

Severity: HIGH (P2) — Potential egress hole if policy not enforced before LLM init

The Issue:
model_info.py:31 makes an httpx.get call:

response = httpx.get(f"{base_url}/v1/model/info", headers=headers)

This is called from LLM._init_model_info_and_caps() (llm.py:619), which runs in post_init (during LLM object construction).

The call is gated on:

if model.startswith("litellm_proxy/") and base_url:

But the execution sequence matters:

  1. In the agent-server, enforce_agent_llm_policy() is called at conversation start
  2. This clamps the LLM model/base_url BEFORE an LLM object is constructed
  3. So by the time _init_model_info_and_caps runs, the policy should have already filtered off-box models

However:

  • The SDK guard is the ONLY chokepoint if an LLM is constructed outside the agent-server (e.g., in unit tests, local SDK usage)
  • If a model starts with "litellm_proxy/" but base_url points off-box, the call proceeds
  • The _zentra_airgap.py guard in _prepare_transport_kwargs (line 2051) only fires on COMPLETION calls, not on post_init

Risk:
If the policy enforcement order changes or an LLM is constructed outside the agent-server path, an off-box base_url could trigger the httpx.get before the SDK call-boundary guard fires.

Code evidence:

# llm.py:619 (__post_init__)
self._init_model_info_and_caps()

# model_info.py:78-82
if model.startswith("litellm_proxy/") and base_url:
    response = httpx.get(f"{base_url}/v1/model/info", headers=headers)  # Unvalidated!

Fix guidance:
Add a call to assert_onbox_target() in _init_model_info_and_caps() BEFORE the httpx.get, OR gate the call on airgap_enforced(). Ensures the base_url is validated to the appliance endpoint before ANY HTTP call.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read vendor/openhands-sdk/openhands/sdk/llm/utils/model_info.py at the model-info request and llm.py at _init_model_info_and_caps() in post_init. Trace how enforce_agent_llm_policy() and the SDK transport guard currently apply. Done means the base_url is validated or the request is gated before httpx.get can run, including when an LLM is constructed outside the agent-server.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.