fix: mitigate TOCTOU DNS rebinding gap in git clone SSRF prevention#633
fix: mitigate TOCTOU DNS rebinding gap in git clone SSRF prevention#633
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Caution Review failedPull request was closed or merged during review WalkthroughAdds TOCTOU DNS-rebinding mitigations to git clone SSRF prevention. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request focuses on enhancing the security of Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #633 +/- ##
==========================================
- Coverage 92.49% 92.47% -0.03%
==========================================
Files 554 554
Lines 27836 27872 +36
Branches 2670 2677 +7
==========================================
+ Hits 25748 25775 +27
- Misses 1647 1654 +7
- Partials 441 443 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive mitigation strategy for TOCTOU DNS rebinding vulnerabilities in git clone operations. The solution effectively addresses the time-of-check-to-time-of-use gap by pinning validated IPs for HTTPS URLs using http.curloptResolve and performing a double-resolve consistency check for SSH/SCP URLs. The changes include new Pydantic models for carrying validation results, helper functions for constructing curloptResolve values, and a dedicated function for verifying DNS consistency. Documentation in CLAUDE.md and docs/design/operations.md has been updated to reflect these security enhancements. The new functionality is thoroughly covered by unit tests, ensuring correctness and robustness.
src/synthorg/tools/git_tools.py
Outdated
| GIT_COMMAND_START, | ||
| hostname=validation.hostname, | ||
| note="toctou_mitigation_skipped", | ||
| ) |
There was a problem hiding this comment.
Using GIT_COMMAND_START for logging when TOCTOU mitigation is skipped might be slightly misleading. GIT_COMMAND_START typically indicates that a command is about to be executed. Consider introducing a more specific log event, such as GIT_CLONE_TOCTOU_MITIGATION_SKIPPED, to clearly differentiate this scenario from an actual command initiation. This would improve log clarity and make it easier to filter relevant events.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CLAUDE.md`:
- Line 138: The note incorrectly points at git_url_validator; update the wording
to point readers to GitCloneTool (the class responsible for injecting
http.curloptResolve) instead, clarifying that git_url_validator only returns
validation data and helpers while GitCloneTool performs the actual HTTPS clone
path resolution; change the reference text to mention GitCloneTool (and
optionally its module synthorg.tools.git_tools) and explain that the
curloptResolve injection occurs there so future maintainers edit the correct
location.
In `@src/synthorg/tools/git_tools.py`:
- Around line 685-692: The branch that returns early when
validation.resolved_ips is empty is emitting GIT_COMMAND_START even though no
git subprocess is launched; change this to emit a dedicated skip event (e.g.,
GIT_MITIGATION_SKIPPED or GIT_CLONE_MITIGATION_SKIPPED) instead of
GIT_COMMAND_START in the logger.debug call inside the if not
validation.resolved_ips block, keeping the same metadata (hostname and note) and
returning args as before; add the new event constant if it doesn't exist and
update any event consumers/tests accordingly to expect the mitigation-skip event
rather than a git.command.start event.
- Around line 694-706: The DNS-pinning branch currently unconditionally injects
http.curloptResolve (in the block using validation.is_https,
build_curl_resolve_value, and logging GIT_CLONE_DNS_PINNED) but must first
verify the Git binary supports that config (support added in Git v2.37.0); add a
runtime capability check (e.g., call a helper like get_git_version or run `git
--version` and parse/compare to 2.37.0) before returning ["-c",
f"http.curloptResolve={resolve_value}", *args], and if the Git version is older,
raise/return a clear error explaining that DNS-pinning requires Git >= 2.37.0
(do not silently fall back). Ensure the check happens at clone time in the same
code path so the clone fails fast with a descriptive message when unsupported.
In `@src/synthorg/tools/git_url_validator.py`:
- Around line 310-312: Before raising the ValueError in the block that checks
"if not ips" (the code that sets msg = "ips must not be empty" then raises
ValueError), log the error with context at WARNING or ERROR level (e.g.,
logger.error or logger.warning) including the message and relevant context (the
ips variable and any request/remote info available) and then raise the
ValueError as before; ensure you use the module logger (logger =
logging.getLogger(__name__) if not already defined) and keep the log message and
the raised msg consistent.
In `@tests/unit/tools/git/test_git_clone.py`:
- Around line 341-366: The test test_mitigation_disabled_skips_pinning currently
never verifies that GitCloneTool forwards
GitCloneNetworkPolicy(dns_rebinding_mitigation=False) into
validate_clone_url_host because the stubbed _mock_validate returns
resolved_ips=() unconditionally; update the test so the validator stub asserts
it received the policy (or make _mock_validate accept an expected_policy and
raise/assert if received.policy.dns_rebinding_mitigation is not False) or
replace the stub with the real validator and mock DNS resolution; ensure the
assertion verifies that validate_clone_url_host was called with a policy whose
dns_rebinding_mitigation is False (referencing GitCloneTool,
GitCloneNetworkPolicy, validate_clone_url_host, _mock_validate, and captured).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4bdf83d7-9994-4132-9dda-de24a49d5114
📒 Files selected for processing (9)
CLAUDE.mddocs/design/operations.mdsrc/synthorg/observability/events/git.pysrc/synthorg/tools/git_tools.pysrc/synthorg/tools/git_url_validator.pytests/unit/tools/git/conftest.pytests/unit/tools/git/test_git_clone.pytests/unit/tools/git/test_git_url_validator.pytests/unit/tools/git/test_git_url_validator_toctou.py
9e7d844 to
2360a23
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/synthorg/tools/git_tools.py (1)
696-709:⚠️ Potential issue | 🟠 MajorGate DNS pinning on Git version capability check.
The comment states "git >= 2.22" but
http.curloptResolvewas introduced in Git v2.37.0. On older versions, the config is silently ignored—Git will not error, but DNS pinning fails silently, leaving HTTPS clones unprotected against DNS rebinding.Either:
- Add a runtime version check and fail with a clear error if Git < 2.37.0, or
- At minimum, correct the comment and document in
operations.mdthat this protection requires Git >= 2.37.0Git http.curloptResolve minimum version requirement🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/tools/git_tools.py` around lines 696 - 709, The DNS-pinning branch currently assumes http.curloptResolve is supported but that option only exists in Git >= 2.37.0, so update the logic that runs when validation.is_https (the block using build_curl_resolve_value and returning ["-c", f"http.curloptResolve={resolve_value}", *args]) to first check Git’s runtime version (e.g., run and parse `git --version`) and require >= 2.37.0; if the installed Git is older, either raise a clear error explaining the requirement or log an explicit failure and abort the clone instead of silently returning the config, and keep the GIT_CLONE_DNS_PINNED log to include version info so operators know why DNS pinning wasn’t applied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/operations.md`:
- Around line 514-515: The docs incorrectly state that git >= 2.22 supports
http.curloptResolve; update the text to require git >= 2.37.0 and adjust the
sentence referencing `http.curloptResolve=host:port:ip` (and any other
occurrences of "git >= 2.22") to read "git >= 2.37.0" so the documented minimum
Git version matches the actual introduction of that feature.
In `@src/synthorg/tools/git_url_validator.py`:
- Around line 564-568: This path that returns for an invalid https port should
log a WARNING with context before returning: when raw_port is not None and
raw_port <= 0, emit a warning (using the same logger used elsewhere in this
module, e.g., logger.warning or process_logger.warning) including the clone URL
and the invalid raw_port value, then return the error string; mirror the
wording/format used in the other error paths (lines ~543-560) for consistency
while keeping the return value unchanged.
In `@tests/unit/tools/git/test_git_clone.py`:
- Around line 165-174: The helper _mock_validate currently types the inner
coroutine parameter policy as Any; update the signature so policy is typed as
GitCloneNetworkPolicy to match the real validate_clone_url_host and catch future
signature mismatches—i.e., change the async def _inner(url: str, policy: Any) ->
DnsValidationOk to use GitCloneNetworkPolicy for policy (and add/import the type
where needed) while keeping the returned DnsValidationOk and the
monkeypatch.setattr(git_tools_module, "validate_clone_url_host", _inner) logic
unchanged.
---
Duplicate comments:
In `@src/synthorg/tools/git_tools.py`:
- Around line 696-709: The DNS-pinning branch currently assumes
http.curloptResolve is supported but that option only exists in Git >= 2.37.0,
so update the logic that runs when validation.is_https (the block using
build_curl_resolve_value and returning ["-c",
f"http.curloptResolve={resolve_value}", *args]) to first check Git’s runtime
version (e.g., run and parse `git --version`) and require >= 2.37.0; if the
installed Git is older, either raise a clear error explaining the requirement or
log an explicit failure and abort the clone instead of silently returning the
config, and keep the GIT_CLONE_DNS_PINNED log to include version info so
operators know why DNS pinning wasn’t applied.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: fe06fc60-28ff-462b-8a45-7402c4ddf5b8
📒 Files selected for processing (9)
CLAUDE.mddocs/design/operations.mdsrc/synthorg/observability/events/git.pysrc/synthorg/tools/git_tools.pysrc/synthorg/tools/git_url_validator.pytests/unit/tools/git/conftest.pytests/unit/tools/git/test_git_clone.pytests/unit/tools/git/test_git_url_validator.pytests/unit/tools/git/test_git_url_validator_toctou.py
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/tools/git_url_validator.py`:
- Around line 562-574: The code accesses urlparse(url).port directly which can
raise ValueError for malformed ports; update the is_https branch to wrap the
port extraction in a try/except ValueError block so malformed ports are caught,
log the event via logger.warning using the existing GIT_CLONE_SSRF_BLOCKED,
hostname=normalized, port=raw_port (or the raw string), reason="invalid_port",
and return the same "Invalid port in clone URL" message; ensure port is only set
to raw_port or 443 when no exception occurs.
- Around line 303-329: The function build_curl_resolve_value currently treats
IPv6 addresses as not requiring brackets; update its implementation and
docstring to wrap any ip containing ':' in square brackets before joining into
the curl resolve string (so addresses become "[ipv6]" while IPv4 remains
unchanged), and keep the existing empty-ips check/logger behavior
(GIT_CLONE_DNS_FAILED and the ValueError) intact; ensure the returned format
from build_curl_resolve_value is "hostname:port:addr1,addr2,..." with IPv6
entries bracketed to satisfy libcurl parsing.
In `@tests/unit/tools/git/test_git_clone.py`:
- Around line 375-407: The test currently stubs verify_dns_consistency with
mock_verify that returns None but never asserts it was invoked; update the
test_scp_double_resolve_passes setup so the stub records calls (e.g. append
(hostname, expected_ips, dns_timeout) to a list or replace
verify_dns_consistency with a MagicMock) and then assert the recorded call(s)
include the expected hostname "example.com" (and/or expected_ips), or
alternately add a separate assertion or negative-case where mock_verify returns
a non-None string to exercise the TOCTOU mitigation; reference
verify_dns_consistency and mock_verify when making the changes and add an
assertion after tool.execute that the mock was called with the SCP hostname.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: 49736e21-32e9-4c67-8b63-a90ce362f718
📒 Files selected for processing (2)
src/synthorg/tools/git_url_validator.pytests/unit/tools/git/test_git_clone.py
HTTPS URLs: pin git to validated IPs via -c http.curloptResolve (git >= 2.22). SSH/SCP URLs: double-resolve with subset comparison immediately before execution. Both mitigations configurable via GitCloneNetworkPolicy.dns_rebinding_mitigation (default True, disable for CDN/geo-DNS environments). Closes #508 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DnsValidationOk.hostname uses NotBlankStr, port has gt=0/le=65535 - Rename _build_curl_resolve_value to public (cross-module API) - Add empty ips precondition check in build_curl_resolve_value - Extract _ok helper to reduce validate_clone_url_host length - Remove redundant "://" condition in HTTPS port extraction - Add debug log when TOCTOU mitigation is skipped - Split TOCTOU tests into test_git_url_validator_toctou.py (<800 lines) - Deduplicate mock_run_git in test_git_clone.py - Update CLAUDE.md tools/ description with TOCTOU mitigation - Add Git Clone SSRF Prevention section in operations design spec Pre-reviewed by 11 agents, 13 findings addressed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…bbit - Add GIT_CLONE_TOCTOU_SKIPPED event constant (replaces misused GIT_COMMAND_START) - Move DnsValidationOk out of TYPE_CHECKING guard to runtime import - Add control-char check on hostname before curloptResolve interpolation - Guard against port 0 from URL raising unhandled ValidationError - Document SSH TOCTOU residual window as known limitation in module docstring - Document dns_resolution_timeout doubled for SSH in field description - Document block_private_ips=False implicitly disabling TOCTOU mitigation - Improve verify_dns_consistency error message (subset semantics) - Fix _resolve_dns return type ordering for consistency - Add log before ValueError raise in build_curl_resolve_value - Use `is not None` instead of truthiness for rebind_err check - Update execute docstring validation order (add TOCTOU step) - Add comment explaining ValueError unreachability in HTTPS path - Clarify CLAUDE.md tools/ description re curloptResolve injection site - Extract _dns_result helpers to conftest.py (DRY across test files) - Fix module docstring (unit + integration, not just integration) - Fix mock return type annotations to match real signatures - Fix mock _inner parameter types (GitCloneTool, Path | None) - Add SCP-like URL TOCTOU wiring test - Add verify_dns_consistency timeout re-resolution test - Fix test_mitigation_disabled to verify policy forwarding Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add warning log before returning invalid port error (coding guideline) - Type _mock_validate policy param as GitCloneNetworkPolicy instead of Any Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wrap urlparse().port in try/except ValueError for malformed ports - Bracket IPv6 addresses in curloptResolve values per libcurl convention - Assert verify_dns_consistency mock was called with expected hostname in SCP double-resolve test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3c61c89 to
4da0701
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
docs/design/operations.md (1)
514-515:⚠️ Potential issue | 🟡 MinorCorrect the Git version requirement.
The documentation states "git >= 2.22" but
http.curloptResolvewas introduced in Git 2.37.0. A previous review comment flagged this same issue.📝 Suggested fix
- **HTTPS URLs:** Validated IPs are pinned via `git -c http.curloptResolve=host:port:ip` - (git >= 2.22), so git uses the same addresses the validator checked. + (git >= 2.37), so git uses the same addresses the validator checked.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/design/operations.md` around lines 514 - 515, Update the documentation sentence that references git version support for http.curloptResolve: replace "git >= 2.22" with the correct minimum version "git >= 2.37.0" wherever the clause mentioning `http.curloptResolve` appears (the line describing HTTPS URLs pinned via `git -c http.curloptResolve=host:port:ip`) so the documented Git requirement accurately reflects when `http.curloptResolve` was introduced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/tools/git_tools.py`:
- Around line 696-709: Update the incorrect Git version note from "git >= 2.22"
to "git >= 2.37.0" in both places: the inline comment above the
http.curloptResolve usage in the code path that builds the curl resolve flag
(referenced via validation, build_curl_resolve_value, and GIT_CLONE_DNS_PINNED
in git_tools.py) and the module docstring in git_url_validator.py; additionally
add a runtime check (e.g., in the module that invokes git operations or in a
helper function used by git_url_validator) that queries the git version and
raises/returns an explicit error if git < 2.37.0 to avoid silent no-ops.
In `@tests/unit/tools/git/test_git_clone.py`:
- Around line 250-281: Add a `verify_calls` capture and assertion to the
`test_ssh_double_resolve_passes` test so it mirrors
`test_scp_double_resolve_passes`: create a list (e.g., verify_calls:
list[tuple[str, frozenset[str]]]) and a `mock_verify` that appends (hostname,
expected_ips) to it, monkeypatch `verify_dns_consistency` to that `mock_verify`,
run the test using `GitCloneTool(...).execute(...)` as already done, then assert
`verify_calls` contains the expected tuple for "example.com" to prove the TOCTOU
hook ran for SSH URLs too.
---
Duplicate comments:
In `@docs/design/operations.md`:
- Around line 514-515: Update the documentation sentence that references git
version support for http.curloptResolve: replace "git >= 2.22" with the correct
minimum version "git >= 2.37.0" wherever the clause mentioning
`http.curloptResolve` appears (the line describing HTTPS URLs pinned via `git -c
http.curloptResolve=host:port:ip`) so the documented Git requirement accurately
reflects when `http.curloptResolve` was introduced.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: 164b0ec3-34e8-4066-8fce-05a0485e01df
📒 Files selected for processing (9)
CLAUDE.mddocs/design/operations.mdsrc/synthorg/observability/events/git.pysrc/synthorg/tools/git_tools.pysrc/synthorg/tools/git_url_validator.pytests/unit/tools/git/conftest.pytests/unit/tools/git/test_git_clone.pytests/unit/tools/git/test_git_url_validator.pytests/unit/tools/git/test_git_url_validator_toctou.py
| if validation.is_https: | ||
| # Pin git to validated IPs via curloptResolve (git >= 2.22). | ||
| # resolved_ips is guaranteed non-empty here (guard above). | ||
| resolve_value = build_curl_resolve_value( | ||
| validation.hostname, | ||
| validation.port or 443, | ||
| validation.resolved_ips, | ||
| ) | ||
| logger.info( | ||
| GIT_CLONE_DNS_PINNED, | ||
| hostname=validation.hostname, | ||
| resolve_value=resolve_value, | ||
| ) | ||
| return ["-c", f"http.curloptResolve={resolve_value}", *args] |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
What Git version introduced http.curloptResolve config option?
💡 Result:
http.curloptResolve was introduced in Git v2.37.0. [1][2]
🏁 Script executed:
# Check the actual content at the specified lines in the file
cat -n src/synthorg/tools/git_tools.py | sed -n '696,709p'Repository: Aureliolo/synthorg
Length of output: 762
🏁 Script executed:
# Search for any Git version checks in the codebase
rg "version|2\.37|2\.22" src/synthorg/tools/ -i -A 2 -B 2Repository: Aureliolo/synthorg
Length of output: 5677
🏁 Script executed:
# Look for any Git version requirement documentation or validation
rg "curloptResolve|curl.*resolve" src/synthorg/tools/ -i -A 3 -B 3Repository: Aureliolo/synthorg
Length of output: 7377
🏁 Script executed:
# Search for any Git version requirement enforcement or checks
rg "git.*version|version.*git|subprocess.*git|check.*git" src/synthorg/ -i -A 2 -B 2Repository: Aureliolo/synthorg
Length of output: 4112
🏁 Script executed:
# Look at the git_url_validator module docstring to see what it says about version
head -100 src/synthorg/tools/git_url_validator.pyRepository: Aureliolo/synthorg
Length of output: 4264
🏁 Script executed:
# Search for any documentation on Git requirements
find docs/ -type f -name "*.md" 2>/dev/null | head -20 | xargs grep -l "git.*version\|2\.37\|2\.22" 2>/dev/nullRepository: Aureliolo/synthorg
Length of output: 46
Correct the Git version requirement in two locations: inline comment and module docstring.
The comment at line 697 and the git_url_validator.py module docstring both incorrectly state git >= 2.22. The http.curloptResolve config option was introduced in Git v2.37.0, not 2.22. Older Git versions silently ignore this config, leaving HTTPS clones unprotected.
Fix both occurrences:
src/synthorg/tools/git_tools.pyline 697: change"git >= 2.22"to"git >= 2.37.0"src/synthorg/tools/git_url_validator.pymodule docstring: change"git >= 2.22"to"git >= 2.37.0"
Consider adding a runtime Git version check that fails explicitly if Git < 2.37.0 rather than allowing silent failure.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/tools/git_tools.py` around lines 696 - 709, Update the incorrect
Git version note from "git >= 2.22" to "git >= 2.37.0" in both places: the
inline comment above the http.curloptResolve usage in the code path that builds
the curl resolve flag (referenced via validation, build_curl_resolve_value, and
GIT_CLONE_DNS_PINNED in git_tools.py) and the module docstring in
git_url_validator.py; additionally add a runtime check (e.g., in the module that
invokes git operations or in a helper function used by git_url_validator) that
queries the git version and raises/returns an explicit error if git < 2.37.0 to
avoid silent no-ops.
…tions - Fix http.curloptResolve version from 2.22 to 2.37.0 (feature was introduced in git 2.37.0, not 2.22) - Note sandbox ships git 2.39+ (Debian bookworm) so no runtime version check is needed -- we control the container image - Add verify_calls capture and assertions to test_ssh_double_resolve_passes to prove the TOCTOU hook ran for SSH URLs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.3.10](v0.3.9...v0.3.10) (2026-03-20) ### Bug Fixes * **ci:** generate required secrets in DAST workflow ([#623](#623)) ([6ae297f](6ae297f)) * **cli:** doctor image check reads compose file and fix API docs URL ([#625](#625)) ([5202e53](5202e53)) * **engine:** sanitize error messages in checkpoint reconciliation and compaction summaries ([#632](#632)) ([5394ed7](5394ed7)) * mitigate TOCTOU DNS rebinding gap in git clone SSRF prevention ([#633](#633)) ([1846f6e](1846f6e)) * resolve post-startup log loss, add provider model discovery, and improve setup wizard UX ([#634](#634)) ([2df8d11](2df8d11)) ### Maintenance * bump https://github.com/astral-sh/ruff-pre-commit from v0.15.6 to 0.15.7 ([#628](#628)) ([c641d2c](c641d2c)) * bump python from `584e89d` to `fb83750` in /docker/backend ([#627](#627)) ([1a36eca](1a36eca)) * bump python from `584e89d` to `fb83750` in /docker/sandbox ([#629](#629)) ([fd3e69a](fd3e69a)) * bump the minor-and-patch group across 2 directories with 3 updates ([#630](#630)) ([67d14c4](67d14c4)) * bump the minor-and-patch group with 2 updates ([#631](#631)) ([2e51b60](2e51b60)) * **ci:** add timeout-minutes, harden fuzz script, extend CVE audit ([#626](#626)) ([25420e2](25420e2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
git cloneto validated IPs via-c http.curloptResolve=host:port:ip(git >= 2.22), eliminating the TOCTOU gap entirelyGitCloneNetworkPolicy.dns_rebinding_mitigationtoggle (default: enabled) for CDN/geo-DNS environmentsDnsValidationOkmodel carries resolved IPs from validator to clone toolbuild_curl_resolve_valuehelper constructs the curloptResolve config stringverify_dns_consistencyperforms the SSH/SCP double-resolve checkdocs/design/operations.mdwith SSRF/TOCTOU documentationTest plan
pytest -n auto)TestDnsValidationOk,TestBuildCurlResolveValue,TestVerifyDnsConsistency,TestGitCloneToolToctoutest_git_url_validator_toctou.py(all files < 800 lines)Review coverage
Pre-reviewed by 11 agents: code-reviewer, security-reviewer, python-reviewer, conventions-enforcer, pr-test-analyzer, silent-failure-hunter, type-design-analyzer, async-concurrency-reviewer, logging-audit, docs-consistency, issue-resolution-verifier. 13 findings addressed.
Closes #508
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Observability
Documentation
Tests