Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To fix an S3 image CORS error, configure the bucket to allow the exact origin serving your page and the method the browser actually uses—usually GET. If the request sends custom headers and triggers a preflight, allow those headers too. Then use the browser’s Network panel to check whether the real problem is CORS, object access, an incorrect URL, or a proxy such as CloudFront.

CORS is a browser permission check, not a way to make a private S3 object public. A bucket CORS rule does not override ACLs or other access policies. AWS documents that those permissions continue to apply after CORS is enabled.

What S3 CORS does—and what it does not do

Cross-origin resource sharing (CORS) lets a browser page loaded from one origin request a resource from another. For example, a page at https://www.example.com may request an image from an S3 bucket. The bucket must return CORS response headers that match the browser’s request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CORS is configured on the bucket. It does not grant permission to read the object: the bucket policy, object ownership and access settings, and any other applicable permissions still determine whether the object can be fetched. If the object is private or the URL is wrong, changing CORS alone will not fix it.

Start with a narrow bucket rule

For a page that fetches an image with a straightforward GET, use the exact origin of the page—not the S3 origin. An origin consists of the scheme, hostname, and, if present, port; it has no path or trailing slash. Replace the example below with the origin your JavaScript page actually uses.

[
  {
    "AllowedOrigins": ["https://www.example.com"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": []
  }
]

This is an illustrative starting point. Include HEAD only if your client or another component actually sends that method; a simple image GET does not inherently require it. If the browser sends custom request headers and performs a preflight, add the required header names to AllowedHeaders. S3 supports the methods GET, PUT, POST, DELETE, and HEAD; allow only those your application needs. See AWS’s S3 CORS configuration reference for the accepted configuration fields and rules.

Set the rule in the S3 console

  1. Open the AWS S3 console and select the bucket containing the image.
  2. Open Permissions, find Cross-origin resource sharing (CORS), and choose Edit.
  3. Paste a valid JSON configuration, adjusting the origin, methods, and headers to match the browser request.
  4. Save the configuration, then retry the request and inspect its response in the browser Network panel.

The console expects JSON. A malformed configuration will not work; check brackets, commas, quotation marks, and property names carefully.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Find the request that is actually failing

Do not diagnose from the console error alone. Open your browser’s developer tools, select Network, reproduce the failure, and inspect the image request and any related OPTIONS request. Record:

  • The full request URL and response status.
  • The page’s Origin request header.
  • The request method, such as GET or HEAD.
  • Whether an OPTIONS preflight occurred.
  • For a preflight, Access-Control-Request-Method and Access-Control-Request-Headers.
  • The response’s Access-Control-Allow-Origin, Access-Control-Allow-Methods, and any allowed-header information.

Compare those exact values with the bucket rule. AWS evaluates the rules in order and uses the first matching rule; the origin, method, and requested headers must all match. Consult AWS’s CORS troubleshooting guidance when interpreting the result.

Understand when OPTIONS matters

A browser may send a preflight OPTIONS request before the intended request when the request is not a simple CORS request—for example, when it uses certain custom headers. The preflight asks whether the origin may make the intended method with the requested headers. The bucket rule allows the intended method, such as GET; do not add OPTIONS as an allowed S3 method. Instead, make sure the CORS rule matches the origin, intended method, and requested headers so S3 can answer the preflight.

If a requested header is not allowed, S3 can omit the CORS response headers for the preflight. That can make the browser report a CORS failure even though the underlying issue is a mismatch between the request and rule.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test a preflight with curl

Use this command to check the bucket’s response to a preflight. Substitute the actual object URL and the exact page origin seen in the browser. The hostname format below is an example; use the endpoint and URL that your application really requests.

curl -i -X OPTIONS 
  -H 'Origin: https://www.example.com' 
  -H 'Access-Control-Request-Method: GET' 
  'https://BUCKET.s3.REGION.amazonaws.com/OBJECT'

If the browser’s preflight contains Access-Control-Request-Headers, include that same header and value in the curl request, for example:

  -H 'Access-Control-Request-Headers: authorization,content-type'

Put the additional header on the curl command before the object URL. A matching AWS example returns 200 OK with CORS response headers, but a successful command-line check is not a substitute for comparing the browser’s exact URL, origin, method, and requested headers. The curl command tests the endpoint directly; it does not reproduce browser enforcement or any CDN behavior between the browser and S3.

Separate CORS from image access and response headers

The image request itself fails

Check the status and response body. A missing object, incorrect key, private object, or access-denied response points to URL or permission troubleshooting as well as CORS. Verify the object URL and confirm that the relevant access policy permits the intended read. CORS only controls whether a browser may share a cross-origin response with the page; it does not change that access decision.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The image displays, but JavaScript cannot read metadata

To display image pixels, JavaScript generally does not need permission to inspect arbitrary response headers. If your script must read a custom response header—such as custom S3 metadata—add that response header to ExposeHeaders. Do not confuse this with AllowedHeaders: the latter covers request headers sent by the browser when a preflight is used; ExposeHeaders controls which response headers JavaScript can read.

Use the exact response header names your code needs. Exposing response headers is not a substitute for allowing the page origin and request method.

Check CloudFront and other proxies

If the browser requests an image through CloudFront or another proxy, a correct S3 rule may not be enough. Check the proxy’s behavior as well as the bucket:

  • Confirm that the proxy permits and forwards preflight OPTIONS requests when the browser sends them.
  • Forward the CORS request headers the origin needs, including Origin, Access-Control-Request-Method, and Access-Control-Request-Headers where applicable.
  • Review caching so a response created for one origin is not reused for a different origin without accounting for the Origin header.

A stale or mismatched cached response can make the browser see missing or incorrect CORS headers even when the bucket rule appears correct. Compare the response at the public proxy URL with a direct S3 test to locate where the mismatch enters.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common S3 image CORS errors and fixes

What you observe What to check Likely fix
S3 indicates CORS is not enabled Whether the bucket has a valid CORS configuration Add a valid bucket CORS rule. This does not grant object read access.
The CORS response says the request is not allowed The browser’s actual Origin versus AllowedOrigins Add the intended exact origin or correct a mismatch in scheme, hostname, or port.
The request method does not match The actual method versus AllowedMethods Allow the method the client actually uses, such as GET; add HEAD only if needed.
An OPTIONS preflight fails when custom headers are sent Access-Control-Request-Headers versus AllowedHeaders Allow the required request headers in the bucket rule.
The image loads, but script cannot inspect metadata The needed response header versus ExposeHeaders Expose only the response headers the script needs.
The bucket rule looks right, but browser responses lack correct CORS headers Proxy handling of OPTIONS, forwarded headers, and cache behavior Review forwarding and ensure cached responses account for the requesting origin.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need a screenshot of a page rather than to debug your own S3 image request, ScreenshotNeo can return a PNG, JPEG, WebP, or PDF through a single GET request. For example, with cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for the request options. It accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server offers take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo’s free plan to try it with 1,000 screenshots a month and no card.

FAQ

Should I set AllowedOrigins to a wildcard?

Use the exact application origin when you know it. A wildcard is supported by S3 examples, but it is broader than a rule limited to the site that needs access.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do I need to allow OPTIONS in AllowedMethods?

No. The preflight is an OPTIONS request, but the rule’s allowed method should cover the intended request, such as GET. Match the preflight’s requested method and headers to the rule.

Why does curl work while the browser still reports CORS?

The curl command may not match the browser’s exact origin, headers, URL, or route through a proxy. Compare the browser Network panel values with the test and inspect any CDN response and cache behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.