Your deployment package wins, then layers, then the copy built into the runtime. In Python, the first location searched is the directory where your .zip is unpacked, so a version you ship overrides a layer version, which overrides the runtime version. A scanner that reads only one source can miss the copy that actually runs.
The search order, from the AWS docs
For Python, AWS describes the path like this:
| Priority | Location | What lives there |
|---|---|---|
| 1 | /var/task | Your unpacked .zip deployment package |
| 2 | /opt/python and the layer site packages directory | Layer contents |
| 3 | /var/runtime and the runtime site packages | Libraries included in the runtime, such as the SDK |
AWS says dependencies in your deployment package take precedence over dependencies in layers, and libraries in layers take precedence over versions included in the runtime. You can print the real search path inside a function with sys.path.
Why this matters for security
Three common situations follow from that order.
- A patched library in a layer is ignored. If an old copy of the same package sits in your deployment package, the old copy loads. You fixed the layer and nothing changed.
- A runtime fix does not apply. If you bundle your own copy of a library the runtime also ships, Lambda's update to its copy has no effect on your function. AWS says your deployment takes precedence, so runtime updates to those packages do nothing.
- Mixed versions break. AWS warns that shipping a copy of an SDK dependency such as urllib3 without the SDK itself can fail when the runtime SDK updates.
How to find the copy that runs
- Add a log line at init that prints the version and file path of the package in question, for example the module's version attribute and file attribute.
- Print sys.path in a test invocation and compare with the table above.
- Inspect the .zip for duplicate package directories before deployment.
- For layers, list the files under the layer's python directory in the layer zip.
- Use the AWS documentation for the runtime to see which SDK version it includes.
Make scanners see the whole picture
An SBOM built from your lockfile lists what you meant to ship. It may not list a layer's contents, and it will not list what the runtime image bundles. For an accurate view, scan three things: the function package, each attached layer, and the documented runtime contents. Then compare them for duplicates of the same package.
Reduce ambiguity
- Keep one copy of each package across package, layers and runtime. AWS recommends packaging all your own dependencies, even those the runtime includes.
- Pin versions in lockfiles and build layers from the same lockfile as the function.
- Do not put compiled bytecode cache folders in the package, because AWS notes bytecode built on a different platform may be incompatible.
- Avoid overriding system libraries, which AWS lists as a source of conflicts.
Try it yourself
Click through it at your own pace, or open it full screen.
Look for the same package appearing under more than one parent. Duplicates are the cases where load order decides what runs.
Quick check
Does a layer override my deployment package?
No, for Python the deployment package takes precedence over layers, and layers take precedence over runtime included libraries.
Is this search order the same for every language?
Not necessarily. The order above comes from the AWS Python documentation. Check the page for your runtime.
Safeguard's SBOM and dependency scanning can inventory the packages you ship, and reachability analysis shows which vulnerable code your function actually calls. A free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.