Poisoning a Lambda layer backdoors every function that imports it
Publish a malicious version of a shared Lambda layer and the backdoor runs inside every function that picks it up. You cannot surgically un-poison shared code.
Shared code is shared blast radius. One poisoned Lambda layer version can backdoor a whole fleet of functions at once.
How the attack works
An attacker with lambda:PublishLayerVersion publishes a new version of a shared layer that many functions import, embedding backdoor code. They then call UpdateFunctionConfiguration to repoint functions at the malicious version. Because functions resolve the layer at deploy and cold-start time, the poison spreads silently as functions cycle. On cold start the backdoor makes an outbound callback and reads the function’s execution-role credentials, which are then reused to call S3 and Secrets Manager beyond the function’s normal pattern. CloudTrail records the PublishLayerVersion event and the repointing. In ATT&CK terms this is T1195, Supply Chain Compromise, leading to cloud-account abuse (T1078.004).
Why it works
The layer is trusted by every consumer, broad publishing rights let any principal create a new version, and functions auto-adopt whatever version they are configured for. Over-broad execution roles then turn one poisoned import into wide data reach. The root cause is unrestricted layer publishing plus over-privileged function roles.
How to fix it
The non-obvious move is that you cannot surgically remove code already pulled into a layer; deleting just the bad version leaves functions broken or still pinned mid-deploy. Pin and roll back every consuming function to the last-known-good layer version, and revoke the attacker’s lambda:PublishLayerVersion so it cannot be re-poisoned. Scope the fleet from CloudTrail by enumerating every function configured for the poisoned ARN, then trace each execution role’s API calls in the window. Treat every credential those functions could reach as compromised and rotate it. Then restrict publishing to the pipeline identity, require version pinning and provenance verification, and scope each function role to least privilege.
Practice it
We built this as a GraphLattice Range scenario so developers can roll the fleet back to known-good, cut publish rights, and rotate every reachable credential.