Module A-1·30 min read

Running non-root users, managing secrets without leaking them, dropping capabilities, and image scanning.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Introduction

Containers are excellent for isolation, but they are not a silver bullet for security. If a hacker breaches your Node.js application, what can they do to the rest of the host machine?

Unfortunately, the default configuration for most Docker images is inherently insecure. By default, applications run as the root user, which violates the Principle of Least Privilege.

In this module, we will explore the Architect-level skills required to harden a container: transitioning to non-root users, managing secrets securely, dropping Linux capabilities, and scanning for vulnerabilities.


The Danger of root in Containers

If you do not specify a user in your Dockerfile, your Node.js application runs as the root user (UID 0).

Because containers share the host's Linux kernel, the root user inside the container is mathematically the exact same root user on the host machine. While Namespaces and cgroups try to contain this user, a container breakout vulnerability could allow the attacker to execute commands as root directly on your host server.

The Solution: The USER Instruction

You should always run your application as a heavily restricted, unprivileged user.

Official Node.js images come with a built-in unprivileged user conveniently named node (UID 1000). You just have to activate it before executing your application:

dockerfile

[!IMPORTANT] Always place USER node at the very end of your Dockerfile. You still need root permissions to use apk add or to copy files into the container. Switch to node right before the CMD.


Managing Secrets Securely

How do you pass API keys, database passwords, and JWT secrets to your container without leaking them?

The Anti-Pattern: Baking Secrets into Images

dockerfile

If you hardcode secrets in a Dockerfile, anyone who pulls the image or views the source code has your credentials. Even if you try to RUN rm secrets.txt in a later layer, the secret is still permanently embedded in the earlier read-only layer of the OverlayFS.

Method 1: Environment Variables at Runtime

The most common approach is injecting secrets when the container starts.

bash

Or in Compose:

yaml

This is acceptable for most applications, but environment variables can accidentally leak through application crash logs or debugging endpoints (e.g., if a developer logs process.env).

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.