diff --git a/plugins/repository-s3/src/main/java/org/elasticsearch/cloud/aws/blobstore/S3BlobContainer.java b/plugins/repository-s3/src/main/java/org/elasticsearch/cloud/aws/blobstore/S3BlobContainer.java
index 5e014ab3ecd..69955fb5460 100644
--- a/plugins/repository-s3/src/main/java/org/elasticsearch/cloud/aws/blobstore/S3BlobContainer.java
+++ b/plugins/repository-s3/src/main/java/org/elasticsearch/cloud/aws/blobstore/S3BlobContainer.java
@@ -26,6 +26,7 @@ import com.amazonaws.services.s3.model.ObjectListing;
 import com.amazonaws.services.s3.model.ObjectMetadata;
 import com.amazonaws.services.s3.model.S3Object;
 import com.amazonaws.services.s3.model.S3ObjectSummary;
+import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.blobstore.BlobMetaData;
 import org.elasticsearch.common.blobstore.BlobPath;
@@ -40,6 +41,9 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Map;
 
 /**
@@ -60,8 +64,14 @@ public class S3BlobContainer extends AbstractBlobContainer {
     @Override
     public boolean blobExists(String blobName) {
         try {
-            blobStore.client().getObjectMetadata(blobStore.bucket(), buildKey(blobName));
-            return true;
+            return doPrivileged(() -> {
+                try {
+                    blobStore.client().getObjectMetadata(blobStore.bucket(), buildKey(blobName));
+                    return true;
+                } catch (AmazonS3Exception e) {
+                    return false;
+                }
+            });
         } catch (AmazonS3Exception e) {
             return false;
         } catch (Throwable e) {
@@ -180,4 +190,19 @@ public class S3BlobContainer extends AbstractBlobContainer {
         return keyPath + blobName;
     }
 
+    /**
+     * +     * Executes a {@link PrivilegedExceptionAction} with privileges enabled.
+     * +
+     */
+    <T> T doPrivileged(PrivilegedExceptionAction<T> operation) throws IOException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new SpecialPermission());
+        }
+        try {
+            return AccessController.doPrivileged(operation);
+        } catch (PrivilegedActionException e) {
+            throw (IOException) e.getException();
+        }
+    }
 }
diff --git a/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy b/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy
index e5f26c3e9d1..1f09cada2e5 100644
--- a/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy
+++ b/plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy
@@ -22,4 +22,16 @@ grant {
   // TODO: get these fixed in aws sdk
   permission java.lang.RuntimePermission "accessDeclaredMembers";
   permission java.lang.RuntimePermission "getClassLoader";
+  // Needed because of problems in AmazonS3Client:
+  // When no region is set on a AmazonS3Client instance, the
+  // AWS SDK loads all known partitions from a JSON file and
+  // uses a Jackson's ObjectMapper for that: this one, in
+  // version 2.5.3 with the default binding options, tries
+  // to suppress access checks of ctor/field/method and thus
+  // requires this special permission. AWS must be fixed to
+  // uses Jackson correctly and have the correct modifiers
+  // on binded classes.
+  // TODO: get these fixed in aws sdk
+  // See https://github.com/aws/aws-sdk-java/issues/766
+  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
 };