Safeguard
Security

@aws-sdk/client-s3: A Practical Security Guide

The @aws-sdk/client-s3 package is the AWS SDK for JavaScript v3 S3 client. Here is how to use it securely, from credential handling to why v2 is now end-of-support.

Karan Patel
Platform Engineer
6 min read

The @aws-sdk/client-s3 package is the modular Amazon S3 client from the AWS SDK for JavaScript v3, and using it securely is less about the library's own code, which is well maintained, and more about how you supply credentials, scope permissions, and generate presigned access, because that is where nearly every real S3 incident originates. If you are on the aws-sdk client-s3 v3 client, you have already made the most important security decision correctly, because the monolithic v2 aws-sdk package reached end-of-support on September 8, 2025 and no longer receives updates.

The v3 design change that matters here is modularity. Instead of importing the entire AWS SDK, you install only the service clients you need, so @aws-sdk/client-s3 brings in the S3 API and little else. This shrinks your dependency footprint and, by extension, the surface a scanner has to worry about. Related modular clients follow the same pattern, @aws-sdk/client-dynamodb for DynamoDB, @aws-sdk/client-cognito-identity-provider for Cognito user pools, each installed independently.

Migrate off v2

Start with the non-negotiable fact. The v2 aws-sdk package hit end-of-support on September 8, 2025. End-of-support means no security patches, so any vulnerability discovered in v2 after that date stays unpatched forever. If any part of your codebase still imports the monolithic aws-sdk, that is a dependency to migrate, not a decision to defer. The v3 clients like @aws-sdk/client-s3 are the supported path, and staying on an end-of-support SDK is one of the clearer findings a software composition analysis scan will raise, because it is unambiguous: unmaintained code with cloud credentials attached.

Never hardcode credentials

The most common S3 security failure has nothing to do with the SDK version. It is credentials committed to source or baked into an image. The v3 SDK's default credential provider chain exists precisely so you never have to pass keys explicitly: on EC2, ECS, or Lambda it picks up the attached IAM role automatically, and locally it reads your configured profile. Construct the client with no explicit credentials and let the chain resolve them:

import { S3Client } from "@aws-sdk/client-s3";

const s3 = new S3Client({ region: "us-east-1" });

If you find yourself writing credentials: { accessKeyId, secretAccessKey } with literal strings, stop. Those strings end up in git history, get scanned by bots the moment the repo is visible, and are the single fastest path to a compromised AWS account. Use IAM roles for anything running in AWS, and short-lived credentials from a secrets manager or SSO for local development.

Scope the IAM policy tightly

The SDK acts with whatever permissions its credentials carry, so an over-broad IAM policy is an over-broad blast radius. A client that only reads objects from one bucket should have a policy allowing exactly s3:GetObject on that bucket's ARN, not s3:* on *. The most damaging S3 exposures happen when an application role has wildcard S3 permissions and an application bug or a leaked credential turns that into "read or delete every bucket in the account." Grant the specific actions on the specific resources the code actually uses, and revisit the policy when the code changes. Least privilege is the control that limits damage when, not if, something else goes wrong.

Presigned URLs: powerful and easy to misuse

@aws-sdk/client-s3 pairs with @aws-sdk/s3-request-presigner to generate presigned URLs, time-limited links that let a client upload or download an object without AWS credentials. They are the right tool for browser uploads and temporary downloads, but they carry two footguns. First, expiration: set the shortest expiresIn that works for your flow, because a presigned URL is a bearer token, anyone who has the link can use it until it expires. A URL valid for seven days that leaks into a log or a referrer header is a seven-day exposure. Second, scope: a presigned PUT URL should target a specific key, not a pattern that lets the holder overwrite arbitrary objects. Generate presigned URLs server-side, scoped to one operation on one key, with a tight expiry.

Keep the client patched and encrypt in transit and at rest

The v3 SDK releases frequently, with the S3 client currently on the 3.x line and new versions landing regularly. Staying reasonably current means you pick up fixes without drama, and a scanner will flag the client if it drifts far enough behind that a known issue applies. Beyond the client, enforce TLS for all S3 traffic, which the SDK does by default over HTTPS endpoints, and enable server-side encryption on the bucket so objects are encrypted at rest. Neither is the SDK's job to enforce, but both are part of using it responsibly.

A note on testing: aws-sdk-client-mock

Teams testing code that uses @aws-sdk/client-s3 commonly reach for aws-sdk-client-mock, a library that mocks the v3 clients so unit tests do not hit real AWS. It is a test-only dependency and a sensible one, but treat it like any dev dependency: pin it, keep it out of production bundles, and include it in your supply-chain scanning. Mocking the S3 client in tests is good practice, because it keeps tests fast and stops a misconfigured test from touching real buckets or burning real credentials.

FAQ

Is @aws-sdk/client-s3 the current AWS S3 client for JavaScript?

Yes. It is the modular S3 client from AWS SDK for JavaScript v3, currently on the 3.x line with frequent releases. The older monolithic aws-sdk v2 package reached end-of-support on September 8, 2025 and should be migrated off.

How should I provide credentials to the S3 client?

Use the default credential provider chain: attach an IAM role in AWS environments and let the SDK resolve it, or use short-lived credentials locally. Never hardcode access keys in source or images.

Are presigned URLs safe?

They are safe when scoped and short-lived. A presigned URL is a bearer token, so set the shortest practical expiry, scope it to one operation on one object key, and generate it server-side. A long-lived or broadly scoped presigned URL that leaks is a real exposure.

What is aws-sdk-client-mock for?

It mocks the AWS SDK v3 clients so unit tests can exercise S3 code without calling real AWS. It is a test-only dependency; pin it, keep it out of production builds, and scan it like any other dependency.

Never miss an update

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