{"record":{"id":"11d9583ebd35caf1","repo":"spring-projects/spring-ai","slug":"media-url-response-exceeds-maximum-allowed-size-of-11d958","errorCode":null,"errorMessage":"Media URL response exceeds maximum allowed size of  bytes","messagePattern":"Media URL response exceeds maximum allowed size of  bytes","errorType":"exception","errorClass":"java.lang.SecurityException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/MediaFetcher.java","lineNumber":198,"sourceCode":"\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (normalizedHost.equals(normalizedAllowed)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static byte[] readWithSizeLimit(InputStream inputStream, int maxBytes) throws IOException {\n\t\tByteArrayOutputStream output = new ByteArrayOutputStream();\n\t\tbyte[] buffer = new byte[8192];\n\t\tint totalRead = 0;\n\t\tint bytesRead;\n\t\twhile ((bytesRead = inputStream.read(buffer)) != -1) {\n\t\t\ttotalRead += bytesRead;\n\t\t\tif (totalRead > maxBytes) {\n\t\t\t\tthrow new SecurityException(\n\t\t\t\t\t\t\"Media URL response exceeds maximum allowed size of \" + maxBytes + \" bytes\");\n\t\t\t}\n\t\t\toutput.write(buffer, 0, bytesRead);\n\t\t}\n\t\treturn output.toByteArray();\n\t}\n\n\tprivate static RestClient createSsrfSafeRestClient() {\n\t\tRegistry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()\n\t\t\t.register(\"http\", new SsrfBlockingPlainSocketFactory())\n\t\t\t.register(\"https\", new SsrfBlockingSSLSocketFactory(SSLConnectionSocketFactory.getSocketFactory()))\n\t\t\t.build();\n\n\t\tPoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(\n\t\t\t\tsocketFactoryRegistry, null, null, null, null, new SsrfSafeDnsResolver(), null);\n\t\tconnectionManager.setDefaultConnectionConfig(ConnectionConfig.custom()\n\t\t\t.setConnectTimeout(Timeout.ofSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS))\n\t\t\t.setSocketTimeout(Timeout.ofSeconds(DEFAULT_SOCKET_TIMEOUT_SECONDS))","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/MediaFetcher.java#L180-L216","documentation":"MediaFetcher streams the bytes of a user-supplied media URL and enforces a hard cap (maxBytes) on how much it will read. As soon as the cumulative bytes read exceed the limit, it aborts and throws this SecurityException instead of buffering an arbitrarily large response. It protects the JVM from memory exhaustion (denial of service) when a remote URL points at a very large or endless resource.","triggerScenarios":"Calling Bedrock Converse model APIs that include a Media (image/document) whose URL, when fetched via MediaFetcher.fetch/readWithSizeLimit, returns more than the configured maxBytes (default limit) of body bytes before EOF.","commonSituations":"Pointing media URLs at multi-hundred-MB files (e.g. raw video, TIFF scans) instead of reasonable images/PDFs; a misconfigured or hostile endpoint returning an unbounded/huge body; proxies that ignore Range requests and return the full object; limits tightened by a newer library version so previously working media now trips the cap.","solutions":["Serve or point to a smaller media file that fits within the configured maxBytes limit (compress/resize the image, or use a trimmed PDF).","Raise the size limit if legitimately large media is expected, by configuring MediaFetcher with a larger maxBytes value when constructing it.","Verify the URL actually resolves to the intended media and not an oversized default/landing response (e.g. an HTML error page with a huge body).","Catch SecurityException around the model call and return a clear validation message asking the user to supply smaller media."],"exampleFix":"// before\nMedia media = new Media(MimeTypeUtils.IMAGE_JPEG, new URL(\"https://example.com/huge-40mb-image.png\"));\n// after\nMedia media = new Media(MimeTypeUtils.IMAGE_JPEG, new URL(\"https://example.com/resized-4mb-image.jpg\"));\n// or raise the cap:\n// MediaFetcher fetcher = MediaFetcher.withMaxBytes(64 * 1024 * 1024);","handlingStrategy":"validation","validationCode":"// Java: pre-check remote media size via HEAD before including it\nHttpURLConnection c = (HttpURLConnection) mediaUrl.openConnection();\nc.setRequestMethod(\"HEAD\");\nlong len = c.getContentLengthLong();\nlong MAX = 20L * 1024 * 1024; // match your MediaFetcher maxBytes\nif (len > MAX) {\n    throw new IllegalArgumentException(\"Media URL body \" + len + \" bytes exceeds limit \" + MAX);\n}","typeGuard":null,"tryCatchPattern":"try {\n    model.call(prompt);\n} catch (SecurityException e) {\n    if (e.getMessage().contains(\"exceeds maximum allowed size\")) {\n        // reject media, ask user for a smaller file\n    } else { throw e; }\n}","preventionTips":["Always pre-check Content-Length with a HEAD request for remote media URLs.","Serve media from a CDN that supports compression/resizing and keep assets small.","Configure MediaFetcher maxBytes deliberately and document it alongside your media pipeline limits.","Reject oversized uploads at your own API boundary before URLs ever reach the model."],"tags":["security","ssrf-protection","media","size-limit","bedrock"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}