iOfficeAI/OfficeCLI · error · ArgumentException

Remote {what} at {url} exceeds {max / (1024 * 1024)} MB limi

Error message

Remote {what} at {url} exceeds {max / (1024 * 1024)} MB limit.

What it means

Thrown by SsrfGuard.ReadBounded once the remote body has streamed more than the byte cap (default SsrfGuard.MaxRemoteBytes = 100 MB). It bounds memory on a hostile or accidentally-huge response because the default HttpClient buffering ceiling (~2 GB) is far above any legitimate asset. Callers are expected to also pre-check Content-Length to fail fast on honest servers.

Source

Thrown at src/officecli/Core/SsrfGuard.cs:98

    /// <summary>
    /// Copy <paramref name="src"/> into memory, refusing once <paramref name="max"/>
    /// bytes have been read. Use after <see cref="CreateGuardedHandler"/> so a
    /// chunked / Content-Length-lying response cannot exhaust memory. Callers
    /// should still pre-check <c>response.Content.Headers.ContentLength</c> to
    /// fail fast when the server is honest about an oversized body.
    /// </summary>
    /// <param name="what">Noun used in the refusal message, e.g. "image" or "file".</param>
    public static byte[] ReadBounded(Stream src, long max, string url, string what = "file")
    {
        using var ms = new MemoryStream();
        var buf = new byte[81920];
        long total = 0;
        int n;
        while ((n = src.Read(buf, 0, buf.Length)) > 0)
        {
            total += n;
            if (total > max)
                throw new ArgumentException(
                    $"Remote {what} at {url} exceeds {max / (1024 * 1024)} MB limit.");
            ms.Write(buf, 0, n);
        }
        return ms.ToArray();
    }

    /// <summary>
    /// True only for globally-routable addresses. Blocks loopback, private
    /// (RFC1918), link-local (incl. 169.254.0.0/16 cloud-metadata), unique-local
    /// IPv6 (fc00::/7), multicast and unspecified — the SSRF target ranges.
    /// </summary>
    public static bool IsPublicAddress(IPAddress address)
    {
        var addr = address.IsIPv4MappedToIPv6 ? address.MapToIPv4() : address;

        if (IPAddress.IsLoopback(addr)) return false;
        if (addr.Equals(IPAddress.Any) || addr.Equals(IPAddress.IPv6Any)) return false;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Point at a smaller, appropriately-sized asset (resize images, trim data).
  2. Pre-check response.Content.Headers.ContentLength against your limit and reject before streaming.
  3. Host the file locally instead of fetching a huge remote blob.

Example fix

// before (client side, before ReadBounded)
var resp = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
var len = resp.Content.Headers.ContentLength ?? -1;
if (len is 0 or -1 || len > SsrfGuard.MaxRemoteBytes) return; // fail fast on honest servers
using var s = await resp.Content.ReadAsStreamAsync();
var bytes = SsrfGuard.ReadBounded(s, SsrfGuard.MaxRemoteBytes, url);
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check Content-Length when the server is honest about size
long len = resp.Content.Headers.ContentLength ?? -1;
if (len > SsrfGuard.MaxRemoteBytes)
    throw new InvalidOperationException("remote asset too large before download");

Try / catch

try { bytes = SsrfGuard.ReadBounded(stream, max, url, "image"); }
catch (System.ArgumentException ex) when (ex.Message.Contains("MB limit"))
{ /* asset exceeded the size cap; use a smaller source */ }

Prevention

When it happens

Trigger: An image=/data=/media=/model3d= URL whose response body exceeds the cap; a streaming/chunked response with no Content-Length that keeps sending; pointing at a large downloadable file by mistake.

Common situations: Linking to a full-resolution raw asset; a CDN returning a larger variant than expected; an unbounded server stream.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/5b3174b6e12823bd. Report an issue: GitHub.