Skip to content

F-030: fix(security): enforce loopback-only ollama_host#30

Open
Sephyi wants to merge 1 commit intodevelopmentfrom
audit/f-030-ollama-url-loopback
Open

F-030: fix(security): enforce loopback-only ollama_host#30
Sephyi wants to merge 1 commit intodevelopmentfrom
audit/f-030-ollama-url-loopback

Conversation

@Sephyi
Copy link
Copy Markdown
Owner

@Sephyi Sephyi commented Apr 22, 2026

Summary

fix(security): enforce loopback-only ollama_host.

Audit context

Closes audit entry F-030 from #3.

Verification

  • cargo fmt --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test --all-targets

Note: one pre-existing test porcelain_exits_within_timeout_with_no_staged_changes is a known macOS cold-start flake that reproduces on unmodified development — unrelated to this change.

Previous validation only checked that `ollama_host` started with an
`http://` or `https://` scheme. A malicious or compromised config could
point it at any remote URL, redirecting staged diff traffic (source
code, potentially sensitive context) to an attacker-controlled host.

Parse the configured URL with the `url` crate and reject any host that
is not:

- `127.0.0.0/8` IPv4 loopback range (via `Ipv4Addr::is_loopback`)
- `::1` IPv6 loopback (via `Ipv6Addr::is_loopback`)
- the literal string `localhost` (ASCII case-insensitive)

DNS is intentionally *not* resolved — a hostname other than `localhost`
is rejected even if it would resolve to a loopback address, because the
resolver cannot be trusted at config time and a local DNS hijack could
otherwise bypass the check.

Existing integration tests that build URLs from `wiremock::MockServer`
continue to pass because mock servers bind to `127.0.0.1`, and those
tests construct `Config` directly without going through `Config::load`.

Add 11 unit tests covering localhost (mixed case), 127.0.0.1,
127.x.x.x, [::1], https scheme, public IPv4 (8.8.8.8), RFC1918
(192.168.x.x), public hostname, public IPv6 (2001:db8::1), and
malformed URL rejection.

Closes audit entry F-030 from #3.
Copilot AI review requested due to automatic review settings April 22, 2026 19:51
@Sephyi Sephyi added the audit Codebase audit cleanup (issue #3) label Apr 22, 2026
@Sephyi Sephyi self-assigned this Apr 22, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses audit finding F-030 by enforcing that the configured ollama_host points only to a loopback address, preventing staged diff traffic from being redirected to arbitrary remote endpoints.

Changes:

  • Add loopback-only validation for ollama_host during config validation.
  • Introduce unit tests covering accepted/rejected loopback host cases.
  • Add the url crate dependency to robustly parse and inspect the configured URL.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/config.rs Adds ollama_host loopback enforcement via URL parsing and corresponding unit tests.
Cargo.toml Adds url dependency needed for ollama_host validation.
Cargo.lock Updates lockfile to include the new direct dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/config.rs
Comment on lines +748 to +761
let url = Url::parse(raw)
.map_err(|e| Error::Config(format!("ollama_host is not a valid URL: {e} (got '{raw}')")))?;

let host = url.host().ok_or_else(|| {
Error::Config(format!(
"ollama_host must include a host component, got '{raw}'"
))
})?;

let is_loopback = match host {
Host::Domain(name) => name.eq_ignore_ascii_case("localhost"),
Host::Ipv4(addr) => IpAddr::V4(addr).is_loopback(),
Host::Ipv6(addr) => IpAddr::V6(addr).is_loopback(),
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

audit Codebase audit cleanup (issue #3)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants