[pull] preview from makeplane:preview#50
Merged
Conversation
#9163) * fix(api): harden webhook & link-unfurl SSRF (advisory clusters A/B/C) Resolves three overlapping SSRF advisory clusters around webhook delivery and work-item link unfurling: - Cluster A (private-IP validation + PATCH bypass): the webhook PATCH handler passed context={request: request} (the request object as the dict key) so the loopback/disallowed-domain guard silently no-op'd — now context={"request": request}. Hardened IP classification (is_blocked_ip) to also block multicast, unspecified, CGNAT (100.64.0.0/10), and IPv4 embedded in IPv6 transition addresses (IPv4-mapped, NAT64, 6to4, Teredo), robust across Python versions. - Cluster B (DNS-rebinding TOCTOU): validators resolved DNS, then requests resolved it again at connect time. New pinned-IP client (plane/utils/url_security.py) resolves+validates once and connects to the validated IP literal so urllib3 performs no second lookup, while preserving Host header, TLS SNI and certificate verification against the real hostname. - Cluster C (redirect SSRF): webhook delivery never follows redirects; the link crawler follows them manually, re-resolving + re-validating + re-pinning every hop. Also: pin requests==2.33.0 in base.txt (imported directly; the pinning adapter needs the >=2.32 get_connection_with_tls_context hook), and log webhook URL-validation rejections to WebhookLog instead of swallowing them. Tests: new test_url_security.py (pinning, rebinding, redirect re-validation, IP edge cases, TLS SNI) + updated link-task tests. Full unit suite: 178 passed. * fix(api): block OAuth avatar SSRF + add per-advisory SSRF regression tests Verified every SSRF-class advisory against the current code. The webhook / link / favicon reports — including the published CVE-2026-30242 and CVE-2026-39843 and the newer "still bypassable" reports (DNS rebinding GHSA-3856/-fgcv/-9292/-whh3/-4mjx/-6p39/-fv24/-8wvv, IP-classification gaps GHSA-75fg, redirect GHSA-6v37/-jw6g/-mq87) — are resolved by the pinned-IP client + hardened classifier in this branch. The one SSRF family still unresolved was the OAuth avatar path: download_and_upload_avatar() fetched the provider-supplied avatar_url with a raw requests.get (no IP validation, default redirect following), so an attacker-controlled avatar could reach internal addresses and be exfiltrated via the static-asset endpoint (GHSA-cv9p-325g-wmv5, and the avatar hop of the Gitea SSRF GHSA-hx79-5pj5-qh42). It now uses pinned_fetch_following_redirects, which validates + pins every hop and blocks internal targets. Adds test_ssrf_advisories.py: a per-advisory regression map covering webhook IP validation, the PATCH context-key guard, webhook DNS rebinding, webhook redirect, favicon redirect + rebinding, and OAuth avatar SSRF. docker compose test: 199 unit tests pass. * fix(api): address PR review feedback on the SSRF pinned client - url_security: preserve URL-embedded credentials (user:pass@host) as Basic Auth instead of silently dropping them when rewriting to the IP literal (Copilot); bracket IPv6-literal hostnames in the Host header (Copilot); add stream=True support that keeps the session open until the response is closed, and release intermediate redirect hops. - ip_address / work_item_link_task: treat UnicodeError (IDNA failures) from getaddrinfo as a resolution failure, not an uncaught exception (CodeRabbit). - authentication/adapter/base: stream the avatar download so the size cap actually bounds memory, upload the size-bounded buffer (not response.content), and always close the response (CodeRabbit, major). - tests: cover auth preservation, IPv6 Host bracketing, IDNA handling, and streamed session lifetime; drop an unused import. docker compose test: 204 unit tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )