Whose day is it on Tuesday?
I mean, Wednesday is Odin’s day, Thursday is Thor’s day, and Friday is Frigg’s day, or Freya’s, depending on who you ask. But what about Tuesday? Who is the god of Tuesday?

It’s Týr, the god of war and justice. In Norse mythology, Týr is known for his bravery and sacrifice, as he lost his hand to the monstrous wolf Fenrir.
Before Odin took over, Týr was the chief god of the Norse pantheon, and that makes sense as Tuesday comes before Wednesday. But did you know the word Týr is of the same root as the following words in other languages?
- Zeus in Greek mythology, the king of the gods.
- Deus in Latin, meaning “god”.
- Deva in Sanskrit, meaning “deity” or “divine being”.
- Div in Persian, meaning “demon” or “evil spirit”!
But why does it mean “demon” in Persian, in contrast to the other languages where it means “god”?

It’s because of an old prophet named Zoroaster, who lived in ancient Persia. He basically invented the concept of good and evil. Before that, gods were just gods, and they could be good or bad. But Zoroaster introduced the idea of a cosmic struggle between good and evil, where the forces of good are represented by Ahura Mazda, and the forces of evil are represented by Angra Mainyu.

So, he branded a class of gods as evil, and the old Indo-European deity went to the dark side in Persian mythology. Funny enough, the exact opposite happened in India, where “deva” came to mean “god”, while “asura” came to mean “demon”.
Just as ancient deities were rebranded as demons over time, our old, trusted code can turn against us, morphing into vulnerabilities known as CVEs.
Attack on Asgard
Thor, the thunder god, enters Valhöll, and seeks Odin’s wisdom. “Odin, CVEs have breached the walls of Asgard! And my hammer, Mjölnir, is not effective against them! The CVEs are made of shadows, and my hammer passes through them like a ghost!”

Odin, the all-father, looks at Thor with a calm expression. “Summon the Docker Commandos at once”, he says.
A portal opens, and the Commandos step out:
- 0. Agent Null, the masked hunter!
- 1. Wilhelmina, aka Mina, the undead assassin!
- 2. Gord, the swordmaster!
- 3. Rothütle, the guy with a red hat!
- 4. Captain Ahab, from the land of the whales!
- 5. The Valkyrie, the fierce warrior!
- 6. Jack, the cyborg soldier!
- 7. Evie, the cowgirl and sharpshooter!

Rothütle steps forward. “Let’s begin the hunt, my friends.”
Kommando 0. Lockdown
As the Commandos enter Asgard, they order the gates to be locked down, so no one can move between the districts of Asgard without being checked. The CVEs were already in the central district, so the Commandos engage them to neutralize the CVEs that were already in the open.

In the case of a CVE outbreak, the first step is to lock down the affected systems and networks to prevent further spread. An example is the recent React2Shell vulnerability (CVE-2025-55182), which allowed remote code execution on servers running vulnerable versions of React. Once the CVE was disclosed, attackers started running crypto miners on compromised servers within hours.
To prevent such attacks, you should:
- Immediately patch the vulnerable software or apply mitigations to prevent exploitation.
- If patching is not possible, consider isolating the affected systems from the network to prevent lateral movement.
- Cut off incoming and outgoing traffic to and from the affected systems until they are secured.
Taking servers down “for maintenance” is most often safer than leaving them vulnerable to exploitation.
Sometimes, you might not even know if you are affected by a CVE, because you don’t know if you are running a vulnerable version of the software. In that case, it’s better to be safe than sorry and lock down the systems until you can verify that they are not affected.
In light of the Log4Shell vulnerability (CVE-2021-44228) outbreak in December 2021, many started generating a list of all the packages and dependencies they were using to check if they were affected, and to prevent future outbreaks.
Kommando 1. SBOM
Rothütle asks Thor if he has a list of all the Asgard residents. Thor replied, “Aye”, and provided them with the records.

Gord says, “Now we can cross-reference the records with the CVE database to identify which residents are CVEs.”
SBOM stands for Software Bill of Materials. It is a list of all the components, libraries, and dependencies that are used in a software project. It includes information about the version of each component, its license, and its vulnerabilities.
Having an SBOM is crucial for security, as it allows you to identify and manage vulnerabilities in your software supply chain. When a CVE is disclosed, you can quickly check if any of the components in your SBOM are affected, and take appropriate action to patch or mitigate the vulnerability.
To generate SBOM for your Docker image, you can use the following command:
$ docker sbom <image>
This command uses Syft under the hood to analyze the image and generate the SBOM. The command is included in Docker Desktop, and is available as a plugin for Docker CLI. As the command is softly being deprecated in favor of the Docker Scout SBOM command, you can also use:
$ docker scout sbom <image>
Or you can use Syft directly.
Kommando 2. Scout
Gord orders Jack, Agent Null, and Mina to scout the remaining districts of Asgard, where the CVEs might be hiding.

Mina says, “Gear up, ladies!” Null replies, “Let’s go hunt some CVEs!”
Docker Scout is a security tool to look out for vulnerabilities in your Docker images. It cross-references the SBOM of your image with the CVE database to identify any known vulnerabilities in the components used in your image. To check for the CVEs:
$ docker scout cves <image>
This command will generate the SBOM for the image, if it doesn’t already exist. If the image already has an SBOM attestation, it will use that instead.
The output will show you the CVEs that are present in the image, along with their severity and any available fixes. You can also get recommendations for how to fix the vulnerabilities:
$ docker scout recommendations <image>
Kommando 3. SBOM Attestations
Gord and Rothütle visit one of the security checkpoints in Asgard. One of the guards says, “Not everyone has an ID card with them, so that their identity can be verified.”
The Valkyrie sets up a camera with face recognition and says, “I can generate an ID card for everyone in Asgard, and attach it to their face. That way, we can verify their identity at the checkpoints.”
A Docker image without an SBOM attestation is like a person without an ID card. You can ask around to see if anyone recognizes them, but you can’t be sure of their identity. To generate an SBOM attestation upon building your image, you can use the following command:
$ docker buildx build --sbom=true -t <org>/<tag> .
This command will build your image, generate the SBOM, and associate them together. Next time you check for CVEs using Docker Scout, it will use the SBOM attestation to identify vulnerabilities in your image.
Generating SBOM attestations is especially important for compiled languages, and for images with multi-stage builds. This is because the build stage often includes many dependencies that are not present in the final image, but can still introduce vulnerabilities if they are not properly managed.
Here is an example of a multi-stage build for a C++ application:
FROM ubuntu:latest AS build
RUN apt-get update && apt-get install -y build-essential
WORKDIR /app
COPY hello.cpp .
RUN g++ -o hello hello.cpp -static
# --------------------
FROM scratch
COPY --from=build /app/hello /hello
CMD ["/hello"]
Here, the build stage includes the build-essential package, which contains compilers and other build tools. The code is compiled into a single static binary, which is then copied into the final image.
If you generate an SBOM afterward using docker sbom, it will be empty, as there are no packages in the final image. But if you generate an SBOM attestation during the build, it can include the build stage dependencies, which can help you identify vulnerabilities in the build stage as well.
To include earlier stages in the SBOM attestation, you can set the following build argument:
ARG BUILDKIT_SBOM_SCAN_STAGE=true
To learn more, check the C++ language guide on Docker’s documentation: https://docs.docker.com/guides/cpp/security/
Kommando 4. Docker Init
Gord tells Thor that the immediate CVE outbreak is under control, but they need to prepare for future outbreaks. “We need to set up a few regulations to ensure better security in the future.”
The first file to look into is the Dockerfile. It is the blueprint for building your Docker image, and it defines the base image, the dependencies, and the commands to run your application. A poorly written Dockerfile can cause security vulnerabilities.
A good way to create a secure Dockerfile is to use the Docker Init command:
$ docker init
It creates the following files and directories based on the language of the project:
Dockerfilecompose.yaml.dockerignoreREADME.Docker.md
The command is deterministic, meaning that running it multiple times will yield the same result. The result uses pre-defined templates based on best practices for containerizing applications in different languages. So, it’s not LLM-based black magic. It asks you a few questions and generates a production-ready setup.
For a Java project, it will generate a three-stage Dockerfile with Eclipse Temurin as the base image.
To learn more about using Docker Init, check out my other JAVAPRO article: How to Containerize a Java Application Securely
Kommando 5. Docker Hardened Images
As Commandos patrol the streets of Asgard, they reach the golden gates of a district. Thor says, “This district is heavily fortified; no CVE can get in here.”

Gord looks into the gates and says, “Hardened Warriors guard this district.”
The district guards leader, a warrior named Artemisia, steps forward and says, “I know how to recognize CVEs.”
Thor says, “You are free to join the Commandos.”
Docker Hardened Images (DHI) are a set of near-zero-CVE base images maintained by Docker, designed for production and development workloads. The Hardened Images were open-sourced in December 2025, and are freely available at dhi.io.
One can use the hardened images for free in their projects:
# Non-hardened Node image
FROM node:24
# Hardened Node image for development
FROM dhi.io/node:24-dev AS build
# Hardened Node image for production
FROM dhi.io/node:24
At the time of writing this article, the hardened images have 0 critical and high CVEs, and only 8 low CVEs that have no fixed versions available. On the contrary, the non-hardened Node image has 9 high CVEs, 17 medium, and 169 low CVEs.
To check for CVEs in the images, you can use Docker Scout:
$ docker scout cves dhi.io/node:24
To check with Trivy:
$ trivy image --scanners vuln dhi.io/node:24
Using hardened base images is probably the most effective way to reduce the attack surface of your application, as it eliminates a large number of vulnerabilities that are present in non-hardened base images.
To learn more about the hardened images, check out my article: Docker Hardened Images are Free
Kommando 6. The Exempted CVEs
Mina returns from her patrol and tells Gord, “I found a few remaining CVEs, but they are not dangerous. We can let them be.”

Not all CVEs are exploitable, especially in the context of a specific application. Some CVEs might be present in the base image, but they might not be relevant to your application if you are not using the vulnerable component.
One can create a list of “Exempted CVEs” that are present in the base image, but are not relevant to the application, so that they don’t show up on your CVE reports and cause unnecessary noise. This is done by the VEX file.
VEX stands for Vulnerability Exploitability eXchange. It is a standardized format for communicating the exploitability of vulnerabilities in software components. A VEX file allows you to specify which CVEs are relevant to your application, and which ones can be safely ignored.
One can create VEX reports manually using the vexctl command:
$ vexctl create \
--author="author@example.com" \
--product="pkg:docker/example/app@v1" \
--subcomponents="pkg:npm/express@4.17.1" \
--vuln="CVE-2022-24999" \
--status="not_affected" \
--justification="vulnerable_code_not_in_execute_path" \
--file="CVE-2022-24999.vex.json"
Some tools might be able to generate VEX reports automatically based on the application’s usage of the vulnerable components.
When checking an image for CVEs, you can specify the VEX file to exclude the Exempted CVEs from the report:
$ docker scout cves <image> --vex-location <directory>
The command will take into account all the VEX statements found in the specified directory, and will exclude the CVEs that are marked as “not affected” or “fixed” in the VEX file from the report.
Kommando 7. VEX Attestation
The Valkyrie issues a few “Check Exemptions” badges for the Exempted CVEs, and adds them to the checkpoints. “The Exempted CVEs can pass through the checkpoints without being flagged, as they are not a threat to us.”

Just like you can generate SBOM attestations during the build process, you can also generate VEX attestations. But it’s slightly more complicated.
To generate a VEX attestation, you first need to build the image and push it to a registry:
$ docker buildx build \
--sbom=true \
--provenance=true \
--push \
-t <org>/<tag> .
This command creates SBOM and provenance attestations for the image, and push them to the registry. Provenance attestations are used to verify the authenticity of the image, and to ensure that it was built in a secure and controlled environment.
Then, you can add a VEX statement to the image using Docker Scout:
$ docker scout attestation add \
--file <cve-id>.vex.json \
--predicate-type https://openvex.dev/ns/v0.2.0 \
<image>
You can alternatively include the VEX statement in the build image by just copying into your image, if you know it ahead of time:
COPY CVE-2022-24999.vex.json /vex/
Docker Scout VEX attestation is more flexible as you can add VEX statements after the image is built.
Kommando 8. Docker Bake
As the Commandos defeated the CVEs in Asgard, they decided to throw a party to celebrate their victory, and discuss the security measures they could implement to prevent future outbreaks.

Throughout the article, we added more and more flags to our Docker build command. These kinds of flags should be written in files, added to version control, and reviewed by the team, just like the code itself. Docker Bake is a tool that allows you to define your build configurations in a file, and then use that file to build your images.
You can put these configurations in a docker-bake.hcl file:
target "default" {
context = "."
dockerfile = "Dockerfile"
tags = [
"gord/hello:latest",
]
attest = [
"type=provenance,mode=max",
"type=sbom",
]
platforms = [
"linux/amd64",
"linux/arm64",
]
}
Then you can build your image using the following command:
$ docker bake
It makes the building experience smoother and more delicious!
You can try this command with a Spring Boot application, in the following repository: https://github.com/DockerSecurity-io/hello
As the party continues, the Valkyrie comes to Rothütle and says, “Agent Null has a fabricated ID card.”
Kommando 9. The Zero-Day
Rothütle looks at the ID card, and says, “This ID card is not real. Does it mean someone is impersonating him?”
Artemisia says, “I suspected him to be a CVE, so I conferred with Valkyrie.”
As they are talking, Agent Null throws a smoke bomb and disappears.

Agent Null is a master of disguise and deception. He was with the Commandos from the beginning, but no one knew his true identity. It is a metaphor for zero-day vulnerabilities, which are vulnerabilities that are not yet known to the public, and therefore do not have a CVE ID or any information about them.
Zero-day vulnerabilities are the most dangerous type of vulnerabilities, as they can be exploited by attackers before they are discovered and patched. To protect against zero-day vulnerabilities, you need to have a strong security posture that includes:
- Defense in depth: Implement multiple layers of security controls to protect against different types of attacks.
- Monitoring and detection: Continuously monitor your systems for suspicious activity, and have a plan in place to respond to potential incidents.
- Incident response: Have a well-defined incident response plan that includes procedures for identifying, containing, and mitigating the impact of a zero-day vulnerability.
Both React2Shell (CVE-2025-55182) and Log4Shell (CVE-2021-44228) were zero-day vulnerabilities that were exploited by attackers before they were publicly disclosed, and both had the highest severity rating of 10.0.
There are many weapons against zero-day vulnerabilities, but one can mention dropping the unnecessary Linux capabilities from the container:
$ docker run --cap-drop=ALL <image>
As well as running the container with a non-root user.
Learn more about Linux capabilities in the book Docker and Kubernetes Security.
The Commandos realize that Agent Null has created the CVE outbreak to distract them, while he is planning to set Angra Mainyu free from his prison in the Black Forest. They all teleport to the Black Forest, to hunt down the hunter.
Read about the first escape of Angra Mainyu in the book “Black Forest Shadow”, and stay tuned for the next chapter of the Docker Commandos!


Interested in Learning More?
Mohammad-Ali A’râbi is a speaker at JCON!
This article dives into Docker-based security and CVE management – and his JCON workshop takes it further with a hands-on deep dive into Java supply chain security.
If you can’t attend live, you can explore many JCON sessions online – definitely worth checking out!