Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

OpenAPI plugin SSRF validator: resolved IP is not pinned for the connection (DNS check-time vs use-time gap)

Đang mở
#14,312 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 4 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
security

Hướng nghiên cứu

Bắt đầu với connectors/openapi_plugin/server_url_validator.py và openapi_runner.py, đặc biệt là validate_server_url và run_operation quanh các dòng được dẫn chiếu. Trước tiên, tái hiện chuỗi tra cứu DNS offline, sau đó xác định cách có thể sử dụng lại địa chỉ đã được kiểm tra cho request mà vẫn giữ nguyên cách xử lý hostname; hoàn tất nghĩa là kết nối không thể tự nó phân giải đến một địa chỉ bị quá trình validation từ chối.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

validate_server_url (connectors/openapi_plugin/server_url_validator.py) protects the
OpenAPI plugin against SSRF by resolving the target host and blocking
private/loopback/link-local/metadata addresses. However, the validated IP is not
reused for the actual request: openapi_runner.run_operation calls
validate_server_url(url, ...) (openapi_runner.py ~L146) with no dns_resolver, then
issues the request via httpx.AsyncClient(...).request(url=<hostname>) (~L172-186),
which re-resolves the hostname independently at connect time. A host that resolves
to a public address during validation and to a private address at connect time
(classic DNS rebinding) passes the check and is then contacted. Because
run_operation also attaches auth_callback credentials to the request, the request
that reaches the rebound address is credential-bearing.

Severity (stated honestly — this is hardening, not a high-severity SSRF)

Impact in the default configuration is low, because other layers already constrain it:

  • The validator forces https by default, and httpx verifies TLS certificates
    (verify=True), so a rebind to e.g. 169.254.169.254 fails the TLS handshake — the
    request is not sent and no credential is disclosed over the default https path. The
    residual over https is a blind connection attempt (TCP connect + ClientHello) to the
    internal IP, not data/credential exfiltration.
  • Full SSRF + credential disclosure via rebinding requires an operator-configured
    http allowed_base_urls entry, or a caller-supplied http_client with
    verify=False, or a host platform that ingests untrusted OpenAPI specs/overrides.
  • The feature is @experimental.

I'm filing this as defense-in-depth: the validator is a deliberate anti-SSRF control,
and pinning the resolved IP closes the one check-time/use-time gap in it.

Reproduction (mechanism; offline)

semantic-kernel 1.44.1. Making getaddrinfo return a public IP on the 1st lookup
(validation) and a link-local IP on the 2nd (connect) shows the validator passes while
the connection target is an address it would have blocked:

import asyncio, socket
from semantic_kernel.connectors.openapi_plugin.server_url_validator import (
    validate_server_url, try_categorize_non_public_address)

HOST, PUBLIC, META = "rebind.example", "93.184.216.34", "169.254.169.254"
_real, n = socket.getaddrinfo, {"i": 0}
def rebinding(host, *a, **k):
    if host == HOST:
        n["i"] += 1
        ip = PUBLIC if n["i"] == 1 else META
        return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", (ip, 0))]
    return _real(host, *a, **k)
socket.getaddrinfo = rebinding

async def main():
    await validate_server_url(f"https://{HOST}/api/op")     # 1st resolution -> public -> PASSES
    connect_ip = socket.getaddrinfo(HOST, 443)[0][4][0]     # 2nd -> 169.254.169.254 (what httpx uses)
    print("validated public; connect IP:", connect_ip, try_categorize_non_public_address(connect_ip))
asyncio.run(main())

I did not stand up a live authoritative rebinding DNS server + real httpx connection;
this demonstrates the resolve-then-connect gap the runner relies on.

Suggested remediation

Resolve once and pin: connect to the validated IP (e.g. a custom httpx transport /
resolver that reuses the vetted address while preserving SNI/Host), or re-validate the
peer IP at connect time. Consider applying the IP check on the allowed_base_urls path
too (it currently matches on hostname strings without resolving), and re-validating
after redirects if a caller-supplied client enables follow_redirects.

Ngôn ngữ chính
C#
Star
28.6k
Fork
4.8k
Merge trung bình
1 ngày 3 giờ
Pull request đã merge (30 ngày)
16

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/semantic-kernel

Tất cả issue của microsoft/semantic-kernel

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.