Safeguard
DevSecOps

Boto3 Security: Using the AWS SDK for Python Safely

Boto3 is the AWS SDK for Python, and how you configure its credentials, sessions, and version pinning decides how much of your AWS account you are putting at risk.

Karan Patel
Platform Engineer
6 min read

Boto3 is Amazon's official AWS SDK for Python, and because nearly every line of boto3 you write ends in an API call that can read or mutate cloud infrastructure, its security comes down to two questions: what credentials does it use, and how much can those credentials do. The library itself is well maintained; the risk lives in how you feed it identity and how current you keep it.

If you have ever hardcoded an access key "just for testing," this guide is for you. Let us go through the failure modes in the order they actually cause incidents.

Never Hardcode Credentials

The single most common boto3 mistake is passing keys straight into the client:

# Do not do this
import boto3
s3 = boto3.client(
    "s3",
    aws_access_key_id="AKIA...",
    aws_secret_access_key="wJal...",
)

Those keys end up in source control, in logs, in the terminal history, and eventually in a public repo. Long-lived AWS access keys leaked on GitHub are one of the most reliably exploited secret types there is; automated scanners find and abuse them within minutes, and the bill lands on you.

Instead, let boto3 resolve credentials from its default provider chain. It checks, in order: environment variables, shared config and credentials files, and then the instance or container role. On real infrastructure the right answer is almost always the last one:

import boto3
# No keys in code. Boto3 picks up the role attached to the
# EC2 instance, ECS task, or Lambda function automatically.
s3 = boto3.client("s3")

For local development, use short-lived credentials from AWS SSO / IAM Identity Center or aws sts assume-role, not a permanent user key sitting in ~/.aws/credentials.

IAM Least Privilege Is the Real Control

Boto3 can only do what its credentials are permitted to do, so the IAM policy behind the credentials is your primary blast-radius limiter. A script that reads from one S3 bucket should have a role scoped to s3:GetObject on that bucket's ARN, not s3:* on *, and certainly not AdministratorAccess.

The pattern I push for: one narrowly scoped role per workload, defined by the specific actions and resources it touches, reviewed when the workload changes. When a boto3 process is compromised, whether through a leaked key or a supply chain issue in a dependency, the damage is bounded by that policy. An over-broad role turns a small foothold into full account takeover.

Sessions, Regions, and Assumed Roles

For anything beyond a one-off script, use an explicit Session rather than the module-level default client. It makes credential scope obvious and lets you assume roles cleanly:

import boto3

session = boto3.Session(profile_name="prod-readonly", region_name="us-east-1")
s3 = session.client("s3")

To act as a different role (cross-account access, for example), use STS to assume it and build a session from the temporary credentials. These are short-lived by design, which is a security win over static keys. Set the region explicitly rather than relying on ambient configuration, so a misconfigured environment does not silently send data to the wrong region, which can be a compliance and data-residency problem, not just a bug.

Keep the boto3 Version Current

Boto3 releases extremely frequently, often several times a week, tracking new AWS service features through its botocore core. As of late 2025 the current line was in the 1.40.x to 1.42.x range, and it keeps moving. That cadence has two security implications.

First, pin for reproducibility but do not fossilize. Pin an exact boto3 version in your lockfile so builds are deterministic, but keep a process to move that pin forward regularly. A boto3 latest version check should be part of routine maintenance, not a once-a-year scramble:

pip index versions boto3     # see available versions
pip install --upgrade boto3

Second, remember boto3 pulls in botocore, s3transfer, and urllib3, and it is usually one of those transitive dependencies, not boto3 itself, that carries a disclosed CVE. A vulnerability in urllib3 affects you through boto3 even though you never imported urllib3 directly. This is exactly the transitive exposure an SCA tool such as Safeguard is designed to catch, because scanning only your direct imports would miss it.

Validate What Comes Back

Treat data returned from AWS as data, not as trusted input to eval or exec. Object metadata, tags, and user-controlled fields in DynamoDB items can contain whatever an earlier writer put there. If you feed an S3 object's contents or a tag value into a shell command or a template, you have an injection path that has nothing to do with AWS and everything to do with trusting remote data. Parameterize, escape, and validate the same way you would for any external input.

Handling Errors Without Leaking

Boto3 raises botocore.exceptions.ClientError with details that can include ARNs, account IDs, and resource names. Log those server-side, but do not echo raw AWS error messages back to end users; they are reconnaissance gifts. Catch the exception, log the detail where only your team can see it, and return a generic failure to the caller.

FAQ

What is boto3 used for?

Boto3 is the official AWS SDK for Python. It lets Python code call AWS services, such as reading and writing S3 objects, launching EC2 instances, querying DynamoDB, or invoking Lambda, through a consistent object-oriented API backed by the lower-level botocore library.

How should boto3 get its credentials?

Through the default credential provider chain, not hardcoded keys. On AWS infrastructure, attach an IAM role to the instance, task, or function and let boto3 discover it automatically. For local work, use short-lived credentials from IAM Identity Center or an assumed role rather than a permanent access key.

What is the latest boto3 version?

Boto3 releases very frequently; as of late 2025 the current versions were in the 1.40.x to 1.42.x range. Because it moves so fast, check pip index versions boto3 for the current release rather than trusting a number in an article, and update your pin on a regular cadence.

Is boto3 itself a security risk?

Boto3 is well maintained, so the risk is rarely a bug in boto3 code. It comes from over-broad IAM permissions, leaked credentials, and disclosed CVEs in its transitive dependencies like botocore, s3transfer, and urllib3. Scope your IAM policies tightly and scan the full dependency tree.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.