langgraph-api 0.9.0.dev3__py3-none-any.whl → 0.9.0.dev4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
langgraph_api/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.0.dev3"
1
+ __version__ = "0.9.0.dev4"
@@ -386,7 +386,26 @@ class WebhookUrlPolicy(TypedDict, total=False):
386
386
  max_url_length: int
387
387
  """Maximum permitted URL length in characters; longer inputs are rejected early."""
388
388
  disable_loopback: bool
389
- """Disallow relative URLs (internal loopback calls) and localhost hostnames when true."""
389
+ """Disallow loopback-flavored webhook targets when true. Defaults to true.
390
+
391
+ Covers all of:
392
+ - Relative URLs (e.g. ``/internal/hook``) that would dispatch via the
393
+ in-process ASGI loopback transport at ``root_path="/noauth"``. These
394
+ bypass authentication and were the auth-bypass primitive behind
395
+ GHSA-q3v5-r5ch-p57j.
396
+ - Absolute URLs whose hostname is ``localhost`` / ``localhost.localdomain``
397
+ / ``host.docker.internal``.
398
+ - Absolute URLs that DNS-resolve into the IPv4 loopback range
399
+ (``127.0.0.0/8``) or IPv6 loopback (``::1/128``) — including
400
+ DNS-rebinding-style attacks where an arbitrary hostname resolves to
401
+ a loopback IP.
402
+
403
+ Operators who intentionally route webhooks to in-process routes
404
+ (e.g. for local development with ``langgraph dev``, or single-host
405
+ docker-compose setups dispatching to ``host.docker.internal``) can
406
+ set this to ``false`` to restore the pre-GHSA behavior. Only do this
407
+ when you control all routes that loopback webhooks can reach.
408
+ """
390
409
  disable_private_ips: bool
391
410
  """Block RFC 1918 / CGN private IP ranges as webhook targets when true.
392
411
 
@@ -426,7 +445,12 @@ def _validate_url_policy(
426
445
  if "max_url_length" not in policy:
427
446
  policy["max_url_length"] = 2048
428
447
  if "disable_loopback" not in policy:
429
- policy["disable_loopback"] = False
448
+ # Secure default — covers GHSA-q3v5-r5ch-p57j (relative-URL ASGI
449
+ # loopback auth bypass) and the broader SSRF surface that the same
450
+ # flag governs via SSRFPolicy.block_localhost. Mirrored at the
451
+ # webhook.py read site so deployments without any webhooks block
452
+ # also get the safe default.
453
+ policy["disable_loopback"] = True
430
454
  if "disable_private_ips" not in policy:
431
455
  policy["disable_private_ips"] = False
432
456
  return policy
langgraph_api/webhook.py CHANGED
@@ -79,7 +79,14 @@ def _get_webhook_config() -> _WebhookConfig:
79
79
  exact_allowed = frozenset(exact_hosts)
80
80
 
81
81
  disable_private_ips = bool(policy_cfg.get("disable_private_ips", False))
82
- disable_loopback = bool(policy_cfg.get("disable_loopback", False))
82
+ # Loopback webhooks are denied by default (covers relative URLs that
83
+ # would dispatch through the in-process ASGI client at root_path=/noauth,
84
+ # plus localhost / 127.x / ::1 / host.docker.internal absolute URLs,
85
+ # plus any hostname that DNS-resolves into the loopback range). This is
86
+ # the fix for GHSA-q3v5-r5ch-p57j: relative-URL webhooks were the auth
87
+ # bypass primitive, and the localhost/loopback IP variants are the
88
+ # broader SSRF surface that the same flag governs via SSRFPolicy.
89
+ disable_loopback = bool(policy_cfg.get("disable_loopback", True))
83
90
 
84
91
  return _WebhookConfig(
85
92
  allowed_domains=allowed_domains,
@@ -111,11 +118,26 @@ async def validate_webhook_url_or_raise(url: str) -> None:
111
118
  if len(url) > wh.max_url_length:
112
119
  raise HTTPException(status_code=422, detail="Webhook URL too long")
113
120
 
114
- # Relative loopback URL (internal route) — not subject to SSRF checks
121
+ # Relative loopback URL (internal route) — dispatched via an in-process
122
+ # ASGI client that mounts under root_path="/noauth", which the auth
123
+ # middleware treats as an auth-bypass marker. Denied by default so a
124
+ # user-supplied webhook URL cannot be turned into an unauthenticated
125
+ # call against the server's own routes (GHSA-q3v5-r5ch-p57j). Operators
126
+ # who intentionally route webhooks to in-process routes can opt back in
127
+ # by setting webhooks.url.disable_loopback to false.
115
128
  if url.startswith("/"):
116
129
  if wh.disable_loopback:
117
130
  raise HTTPException(
118
- status_code=422, detail="Loopback webhooks are disabled"
131
+ status_code=422,
132
+ detail=(
133
+ "Loopback webhooks (relative URLs and localhost) are "
134
+ "disabled by default. They bypass authentication via the "
135
+ "in-process ASGI transport and can be abused to invoke "
136
+ "internal routes as an unauthenticated caller. Set "
137
+ "webhooks.url.disable_loopback to false (in langgraph.json "
138
+ "or via LANGGRAPH_WEBHOOKS) to opt back in — only do so "
139
+ "when you control the mounted routes."
140
+ ),
119
141
  )
120
142
  return
121
143
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.9.0.dev3
3
+ Version: 0.9.0.dev4
4
4
  Author-email: Will Fu-Hinthorn <will@langchain.dev>, Josh Rogers <josh@langchain.dev>, Parker Rule <parker@langchain.dev>
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
@@ -1,4 +1,4 @@
1
- langgraph_api/__init__.py,sha256=rT-z7MS6SjjAW-hNfa1lcceqLHtmubGcbZwqU32848M,27
1
+ langgraph_api/__init__.py,sha256=etrMz_KrjnLluOQExvb90dAxp4ASQ-MKozOsxgHwg8A,27
2
2
  langgraph_api/_factory_utils.py,sha256=5JsiJbg_YocVSryN2jwoZTg03-eyymlWMK6sKCmXwz0,5756
3
3
  langgraph_api/asgi_transport.py,sha256=XApY3lIWBZTMbbsl8dDJzl0cLGirmAGE0SifqZUnXvs,11896
4
4
  langgraph_api/asyncio.py,sha256=c-YE-14N7_AP1GzifsbP14XnhLsmxT2P916KXruerpI,10573
@@ -32,7 +32,7 @@ langgraph_api/stream.py,sha256=W9lrfDWXmCRDLyF_7s2846DNG_b9_-ijoHEUmW-x990,30346
32
32
  langgraph_api/stream_v2.py,sha256=gW98dq9HKsCJ2NxmXzsYGcqBwFH2bSgmoFVNN3aVPOs,9897
33
33
  langgraph_api/traceblock.py,sha256=GhgAtLhAQ8Z8LHtRQq3par-rfPpRBQp2Q7WBACJq1NI,677
34
34
  langgraph_api/validation.py,sha256=XyeKyt7jAICmIlT_b0J0mv2YbwIbNoe4m6zEmfk9gOA,14657
35
- langgraph_api/webhook.py,sha256=pmgiy1lqTveG8XuE5XLG5dLw7Y5P_AsvewYc7FeGV0c,8100
35
+ langgraph_api/webhook.py,sha256=qXEtkE6orek2POeOQmPRsEarJgXIYp-LBrZB-OwITxc,9572
36
36
  langgraph_api/worker.py,sha256=gixTe6SLYqSEARri_Lbii6cT69dMM0iwDC7YKgYgx5E,21160
37
37
  langgraph_api/_checkpointer/__init__.py,sha256=ofJTJLGy7Hsuzhj-2dpfDvrDloM0BzlhTzvZOdR9K8U,2223
38
38
  langgraph_api/_checkpointer/_adapter.py,sha256=1Mdb3B_bg6EQ_3uJfk6ImiobIiAPdaMQVaruDBzVkE8,20833
@@ -65,7 +65,7 @@ langgraph_api/auth/langsmith/backend.py,sha256=Y6-VxD7zfV1jzGdjmQ66CgNa3SenLbo3d
65
65
  langgraph_api/auth/langsmith/client.py,sha256=79kwCVeHU64nsHsxWipfZhf44lM6vfs2nlfTxlJF6LU,4142
66
66
  langgraph_api/config/__init__.py,sha256=hGqZ3_B4wPm3ZuH5wrDFHHBmtOH_qYnFvX9ChmsBNZ8,25159
67
67
  langgraph_api/config/_parse.py,sha256=VXQPKzqtIsZrRy-nUEBMDESBxXzqFRQNiqsvAZeX3HU,3921
68
- langgraph_api/config/schemas.py,sha256=QLaJXr-q2KuVUcD-ODcnMRorek1UJbbSfWL0Oi9MzJY,19580
68
+ langgraph_api/config/schemas.py,sha256=rYqu67fZxmtCOU-Zc1s3265KbRbqK8PmfvfwvrAmd-Q,20863
69
69
  langgraph_api/encryption/__init__.py,sha256=gaCZ00CocSbqSqrDn6XJHaSp2CZCnC8qnrD9G4fbzyI,363
70
70
  langgraph_api/encryption/aes_json.py,sha256=ExLgrthzVYGP4X51TStU2Td_Sn_3-kXHyk6UKTFmzW4,6139
71
71
  langgraph_api/encryption/context.py,sha256=twnDvH3FcC8rlnPOAhI09dLZcxGgMVlplIH2ZpJ-8P4,1121
@@ -228,8 +228,8 @@ langgraph_grpc_common/proto/errors_pb2.py,sha256=JI6x-vBK1AE7DHZ5DQwN1mZWF6C4xTR
228
228
  langgraph_grpc_common/proto/errors_pb2.pyi,sha256=rd3-BYUH8V-aO66taL7OOblaLgdrDtf1Vcd38GUoVVM,2181
229
229
  langgraph_grpc_common/proto/errors_pb2_grpc.py,sha256=2-LwQ0OPGo-NtC0269q7Fw6GPBxnTLYWq3xP5Eq0_YA,886
230
230
  langgraph_grpc_common/proto/errors_pb2_grpc.pyi,sha256=uC9Wnq6uyg488QiONpJ0ba1s_iouQCOYsjd_FDd1XUM,495
231
- langgraph_api-0.9.0.dev3.dist-info/METADATA,sha256=uSDwXIVruhpFKitSJeLY0GYBNIMLEobchCCAap1Vux8,4516
232
- langgraph_api-0.9.0.dev3.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
233
- langgraph_api-0.9.0.dev3.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
234
- langgraph_api-0.9.0.dev3.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
235
- langgraph_api-0.9.0.dev3.dist-info/RECORD,,
231
+ langgraph_api-0.9.0.dev4.dist-info/METADATA,sha256=g_Fq02B-NpB42hrXkLYufVw6c2jlw3s-u-7GE3tfNog,4516
232
+ langgraph_api-0.9.0.dev4.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
233
+ langgraph_api-0.9.0.dev4.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
234
+ langgraph_api-0.9.0.dev4.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
235
+ langgraph_api-0.9.0.dev4.dist-info/RECORD,,