# The Danger of Falling to System Role in AWS SDK Client

AWS SDK Go client fell back to EC2 instance IAM role when user-supplied credentials errored, letting users import internal S3 buckets via the S3 import feature.

- Payout: Research
- Severity: high
- Program: Doyensec client web platform
- Write-up by: Doyensec
- Disclosed: 2022-10-17
- Write-up quality: 7/10
- Original: https://blog.doyensec.com/2022/10/18/cloudsectidbit-dataimport.html
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2022-10-18-cloudsectidbit-dataimport-html
- Tags: area:cloud domain:cloud domain:web impact:data-leak impact:internal-access kind:research platform:research sev:high tech:aws tech:go technique:source-review vuln:access-control vuln:misconfiguration

**Target:** S3 import feature in a Go web application using aws-sdk-go v1
**Root cause:** Error handler set aws_config.credentials = nil and retried ListObjectsV2, causing the SDK credential provider chain to resolve the EC2 instance IAM role instead of anonymous credentials.
**Steps:**
1. Identify the 'Import Data From S3' feature accepting `bucket_name`, `access_key`, `secret_key`, `region` form fields.
2. Submit a request without access_key so AnonymousCredentials is used, or trigger an error path in ListObjectsV2.
3. Error handler executes `aws_config.credentials = nil` then calls `getObjectsList` again.
4. SDK credential chain resolves the EC2 instance role with full internal S3 access.
5. Supply an internal bucket name (harvested from Burp history) as `bucket_name` to list and import its objects.
**How found:** Auditors reviewed AWS SDK client initialization in user-reachable code paths and noticed the error branch nulling credentials, which triggers the provider chain and instance role.
**Exploitation:** Attacker supplies an internal bucket name to the import feature; the retried call signs with the instance role, listing and importing private bucket contents into the attacker's platform data.
**Escalation:** Internal bucket names harvested from application traffic (Burp history) enable targeting private infrastructure buckets.
**Insight:** In user-facing cloud-integration features, grep for `Credentials = nil` or omitted Credentials in error/fallback branches; any nil triggers the provider chain and silently assumes the host's IAM role.

## Proof of concept (copied exactly from the original report)

**Error handler nulls credentials and retries ListObjectsV2**

```
if err != nil {
 if err, awsError := err.(awserr.Error); awsError {
 aws_config.credentials = nil
 getObjectsList(session_init, aws_config, bucket_name)
 }
}
```

**Import handler builds config from user input**

```
req.ParseForm()
 bucket_name := req.Form.Get("bucket_name")
 accessKey := req.Form.Get("access_key")
 secretKey := req.Form.Get("secret_key")
 region := req.Form.Get("region")

 session_init, err := session.NewSession()
 if err != nil {
 return err, nil
 }

 aws_config = &aws.Config{
 Region: region,
 }

 if len(accessKey) > 0 {
 aws_config.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, "")
 } else {
 aws_config.Credentials = credentials.AnonymousCredentials
 }

 objectList, err := getObjectsList(session_init, aws_config, bucket_name)
```

**Nil credentials config triggers provider chain**

```
svc := s3.New(session.Must(session.NewSession(&aws.Config{
 Credentials: <nil_object>,
 Region: aws.String("us-west-2"),
})))
```

