How OfficeCLI SsrfGuard Protects Against SSRF Attacks in Operations

OfficeCLI SsrfGuard prevents Server-Side Request Forgery (SSRF) by enforcing connect-time public-IP validation on every HTTP request, blocking private network addresses, link-local ranges, and cloud metadata endpoints while maintaining redirect safety and enforcing a 100 MB response size limit.

Every remote fetch operation in iOfficeAI/OfficeCLI—whether loading images, files, models, or media—routes through a centralized security layer called SsrfGuard. This shared component ensures that malicious URLs cannot probe internal networks or cloud metadata services, providing uniform protection across all CLI operations that interact with external resources.

Connect-Time IP Validation: The Core Defense

The primary defense mechanism resides in SsrfGuard.CreateGuardedHandler, implemented in src/officecli/Core/SsrfGuard.cs at lines 26-53. This method constructs a SocketsHttpHandler with a custom ConnectCallback that intercepts TCP connections after DNS resolution but before the socket opens.

When a connection attempt begins, the callback enumerates all IP addresses returned by DNS resolution and validates each through IsPublicAddress. Any address matching the following criteria triggers an immediate ArgumentException:

  • 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 addresses (169.254.0.0/16), including cloud metadata endpoints
  • CGNAT ranges, multicast addresses, or unspecified addresses

This connect-time validation eliminates DNS-rebinding and Time-of-Check-Time-of-Use (TOCTOU) vulnerabilities because the guard inspects the actual socket address rather than relying solely on the hostname string.

Redirect-Aware Enforcement

Legitimate operations often require following redirects to content delivery networks. Rather than disabling automatic redirects, SsrfGuard sets AllowAutoRedirect = true while ensuring every redirect hop re-enters the same ConnectCallback validation pipeline.

This architectural choice guarantees that an attacker cannot bypass IP restrictions by redirecting from a public endpoint to an internal service. Each intermediate URL undergoes identical DNS resolution and address vetting before any TCP connection establishes.

Memory Safety Through Response Size Limits

Beyond network-level protection, SsrfGuard enforces a hard ceiling on remote payload sizes to prevent memory-exhaustion attacks. The class defines MaxRemoteBytes as 100 MiB (104,857,600 bytes), implemented in src/officecli/Core/SsrfGuard.cs at lines 71-84.

After a request succeeds, callers consume the response body through SsrfGuard.ReadBounded, which streams data continuously and aborts immediately upon exceeding the byte limit. This protection remains effective even when remote servers lie about Content-Length headers, as the enforcement occurs during actual byte consumption rather than header inspection.

Centralized Policy Architecture

Both image fetching and generic file downloading utilize the same guard instance, ensuring consistent policy enforcement. In src/officecli/Core/ImageSource.cs (lines 48-66), the ResolveUrl method instantiates the guard via SsrfGuard.CreateGuardedHandler("image"). Similarly, src/officecli/Core/FileSource.cs (lines 92-112) invokes the same method with the context string "file".

This centralized approach prevents security drift between different resource types. Whether fetching a PNG logo or a dataset CSV, the identical validation logic applies:

  1. URL DetectionImageSource.Resolve or FileSource.Resolve identifies http(s):// schemes
  2. Guard Creation – Handler instantiation with custom ConnectCallback
  3. DNS & Vetting – Resolution and IsPublicAddress validation
  4. Connection – TCP socket creation only for public addresses
  5. Redirect Handling – Automatic hops re-enter validation
  6. Size EnforcementReadBounded streaming with 100 MiB cap

Practical Usage Examples

The following examples demonstrate the guard's behavior in common scenarios:

// Valid public image fetch (succeeds)
var (stream, contentType) = ImageSource.Resolve(
    "https://cdn.example.com/logo.png");

// Private network access attempt (throws ArgumentException)
try
{
    var result = ImageSource.Resolve("http://192.168.1.10/secret.png");
}
catch (ArgumentException ex)
{
    // Output: Refusing to fetch image from non-public address...
    Console.WriteLine(ex.Message);
}

// Oversized file attempt (throws ArgumentException)
try
{
    var (fileStream, ext) = FileSource.Resolve(
        "https://large.example.com/big-video.mp4");
}
catch (ArgumentException ex)
{
    // Output: Remote file exceeds 100 MB limit.
    Console.WriteLine(ex.Message);
}

Each high-level Resolve call automatically executes the complete guard pipeline, allowing developers to fetch remote resources without manually implementing SSRF protections.

Summary

  • Connect-time validation in SsrfGuard.CreateGuardedHandler blocks private and link-local IP addresses at the socket level, preventing DNS-rebinding attacks.
  • Redirect safety ensures every hop in a redirect chain undergoes identical IP vetting through the persistent ConnectCallback.
  • Memory protection via MaxRemoteBytes and ReadBounded enforces a 100 MiB ceiling on all remote responses, regardless of header manipulation.
  • Centralized policy across ImageSource and FileSource guarantees uniform SSRF defenses without code duplication or configuration drift.
  • Zero-trust architecture treats all external URLs as untrusted, with no baked-in whitelists that could introduce bypass vulnerabilities.

Frequently Asked Questions

What types of IP addresses does SsrfGuard block?

SsrfGuard blocks 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 addresses including the 169.254.0.0/16 cloud-metadata range, CGNAT ranges, multicast addresses, and unspecified addresses. Any connection attempt resolving to these ranges throws an ArgumentException before TCP handshake completes.

How does SsrfGuard prevent DNS rebinding attacks?

Traditional SSRF protections often resolve hostnames to IPs once, then connect later, creating a TOCTOU window where DNS responses change between check and use. SsrfGuard's ConnectCallback resolves hostnames during the connection attempt and validates the actual socket address immediately before opening the TCP connection, eliminating the race condition that DNS rebinding exploits.

Can attackers bypass protection using HTTP redirects?

No. While AllowAutoRedirect remains enabled to support legitimate CDNs, every redirect target re-enters the same ConnectCallback validation pipeline. If a redirect points to a private IP address or blocked range, the connection aborts with the same ArgumentException as a direct request, ensuring no bypass through intermediate public endpoints.

What happens when a remote file exceeds the size limit?

When a response stream exceeds SsrfGuard.MaxRemoteBytes (100 MiB), the ReadBounded method aborts the operation and throws an ArgumentException with the message "Remote file exceeds 100 MB limit." This occurs during actual byte streaming rather than header inspection, protecting against servers that provide fraudulent Content-Length values.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →