# SSRFGuard Security in OfficeCLI for External Resources: Connect-Time Validation Architecture

> Learn about SSRFGuard security in OfficeCLI, validating external resource connections at socket time to block private IPs and enforce a 100 MB fetch cap for enhanced safety.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: architecture
- Published: 2026-07-10

---

**OfficeCLI centralizes SSRF protection in [`SsrfGuard.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/SsrfGuard.cs), validating IP addresses at socket connection time to block private networks while enforcing a 100 MB cap on all remote resource fetches.**

OfficeCLI enables embedding of remote assets—images, 3D models, and documents—via URLs that may originate from untrusted user input. To mitigate Server-Side Request Forgery (SSRF) risks against internal infrastructure and cloud metadata services, the tool implements robust **SSRFGuard security in OfficeCLI for external resources** through a low-level network validation layer.

## How the SSRF Guard Validates Connections

### Connect-Time IP Filtering

At the core of the defense is `SsrfGuard.CreateGuardedHandler(string what)`, defined in [`src/officecli/Core/SsrfGuard.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/SsrfGuard.cs) (lines 36‑66). This method returns a `SocketsHttpHandler` configured with a custom `ConnectCallback` that intercepts every TCP connection attempt.

The callback resolves the target hostname to its constituent IP addresses and validates each against a whitelist of publicly routable ranges before allowing the socket to open. This **connect-time validation** eliminates DNS rebinding windows by inspecting the actual IP address used for the transport, not just the DNS response.

### Blocked Address Ranges

The `IsPublicAddress(IPAddress address)` method (lines 10‑39) implements the security policy by rejecting:

- **Loopback** addresses (127.0.0.0/8, ::1)
- **Private RFC 1918** ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- **Link-local** networks including cloud-metadata endpoints (169.254.0.0/16)
- **CGNAT** space (100.64.0.0/10)
- **Multicast** ranges
- **IPv6 unique-local** addresses

If any resolved IP falls within these ranges, the `ConnectCallback` throws an `ArgumentException` with a descriptive security message, terminating the request before data transmission begins.

### Size Limiting and Bounded Reads

To prevent memory exhaustion from maliciously large payloads, the guard enforces a uniform `MaxRemoteBytes = 100 MB` limit across all fetchers. The `ReadBounded` method (lines 81‑103) wraps response streams and aborts reads immediately when the cumulative byte count exceeds this threshold, protecting against both honest large files and crafted chunked responses.

## Integration with External Resource Fetchers

### ImageSource Implementation

The `ImageSource.ResolveUrl` method (lines 42‑60 in [`src/officecli/Core/ImageSource.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/ImageSource.cs)) instantiates a guarded handler via `CreateGuardedHandler("image")` before executing the HTTP request. This ensures that every image fetch—whether from HTTPS URLs or data-URIs—undergoes the same IP validation and size constraints.

### FileSource Implementation

Similarly, `FileSource.ResolveUrl` (lines 74‑96 in [`src/officecli/Core/FileSource.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/FileSource.cs)) applies `CreateGuardedHandler("file")` to generic file downloads including GLB models and document attachments. Both fetchers utilize `ReadBounded` to stream content into memory-safe buffers, ensuring consistent **SSRFGuard security in OfficeCLI for external resources** regardless of asset type.

## Practical Usage Examples

### Fetching Images Safely

When resolving remote images, the guard automatically validates the endpoint:

```csharp
// Returns a stream and the appropriate OpenXml image part type.
// Throws if the URL resolves to a private address or exceeds 100 MB.
var (stream, partType) = ImageSource.Resolve("https://example.com/logo.png");

```

### Fetching Generic Files

For 3D models or other binary assets:

```csharp
// Returns a seekable MemoryStream and inferred file extension.
// SSRF guard blocks private/internal URLs and caps the download size.
var (stream, ext) = FileSource.Resolve("https://assets.example.com/model.glb");
// ext will be ".glb" if the server supplies a matching Content-Type header.

```

### Direct Guard Utilization

For advanced scenarios requiring custom HTTP clients:

```csharp
var handler = SsrfGuard.CreateGuardedHandler("custom");
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) };
var resp = await client.GetAsync("https://public-api.example.org/data");
var data = SsrfGuard.ReadBounded(await resp.Content.ReadAsStreamAsync(),
                                 SsrfGuard.MaxRemoteBytes,
                                 "https://public-api.example.org/data",
                                 "custom");

```

## Summary

- **Connect-time validation** in [`SsrfGuard.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/SsrfGuard.cs) inspects actual socket IPs, preventing DNS rebinding attacks against internal services.
- **Comprehensive range blocking** covers RFC 1918, link-local (including 169.254.0.0/16), and multicast addresses via `IsPublicAddress`.
- **Uniform size enforcement** via `ReadBounded` and `MaxRemoteBytes` limits all remote fetches to 100 MB, preventing memory exhaustion.
- **Centralized architecture** ensures `ImageSource` and `FileSource` share identical security postures through `CreateGuardedHandler`.
- **Redirect safety** maintains protection across up to 10 hops, with each intermediate address undergoing public-range verification.

## Frequently Asked Questions

### How does OfficeCLI prevent DNS rebinding attacks?

OfficeCLI validates IP addresses at socket connection time rather than DNS resolution time. The `ConnectCallback` in `CreateGuardedHandler` resolves the hostname and inspects every candidate IP against `IsPublicAddress` immediately before establishing the TCP connection. This ensures that even if DNS returns different addresses during resolution versus connection, the actual transport endpoint is vetted.

### What specific IP ranges does the SSRF guard block?

According to the source code in [`src/officecli/Core/SsrfGuard.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Core/SsrfGuard.cs), the `IsPublicAddress` method blocks loopback (127.0.0.0/8), private RFC 1918 networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), link-local addresses including AWS/Azure metadata endpoints (169.254.0.0/16), CGNAT (100.64.0.0/10), multicast ranges, and IPv6 unique-local addresses.

### Can developers configure the maximum download size limit?

Currently, the `MaxRemoteBytes` constant is hardcoded to 100 MB in [`SsrfGuard.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/SsrfGuard.cs). While the `ReadBounded` method accepts this as a parameter, both `ImageSource` and `FileSource` utilize the static `MaxRemoteBytes` value, meaning all external resource fetches share this uniform cap without runtime configuration options.

### Does the SSRF guard restrict HTTP redirects?

The guard allows up to 10 redirect hops to support public CDNs, but each redirect target undergoes identical scrutiny. Every intermediate URL is resolved and its IP addresses validated through `IsPublicAddress` during the connection phase, ensuring that redirect chains cannot bypass private network protections.