惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
F
Fortinet All Blogs
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
月光博客
月光博客
爱范儿
爱范儿
博客园_首页
S
Security @ Cisco Blogs
H
Heimdal Security Blog
Cyberwarzone
Cyberwarzone
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tailwind CSS Blog
T
Threatpost
博客园 - 司徒正美
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
S
Security Affairs
AWS News Blog
AWS News Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
NISL@THU
NISL@THU
G
GRAHAM CLULEY
人人都是产品经理
人人都是产品经理
L
LangChain Blog
The Register - Security
The Register - Security
L
LINUX DO - 最新话题
博客园 - 【当耐特】
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Proofpoint News Feed
IT之家
IT之家
云风的 BLOG
云风的 BLOG
量子位
D
Darknet – Hacking Tools, Hacker News & Cyber Security
PCI Perspectives
PCI Perspectives
腾讯CDC
大猫的无限游戏
大猫的无限游戏
美团技术团队
N
News | PayPal Newsroom
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Docker
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Cloudbric
Cloudbric

Sysdig Blog

Masterclass: AI is more than ChatGPT and LLMs CVE-2026-39987 update: How attackers weaponized marimo to deploy a blockchain botnet via HuggingFace Kubernetes 1.36 - New security features 5 steps to securing AI workloads Marimo OSS Python Notebook RCE: From Disclosure to Exploitation in Under 10 Hours Security briefing: March 2026 The Sysdig MCP server is now available in AWS Marketplace Risk isn’t reduced until you take action: How teams resolve issues in the cloud AI infrastructure security: Why it deserves its own category Three pillars for building effective runtime-powered cloud defense, the right way Closing the cloud security gap with runtime security Seeing risk isn’t stopping it: Why visibility alone isn’t enough TeamPCP expands: Supply chain compromise spreads from Trivy to Checkmarx GitHub Actions AI coding agents are running on your machines — Do you know what they're doing? Runtime security for AI coding agents: Protecting AI-assisted development How runtime insights power every cloud security use case CVE-2026-33017: How attackers compromised Langflow AI pipelines in 20 hours Inline Cloud Response: Accelerating AWS threat containment for SOC teams Runtime malware detection for AWS Fargate Detecting CVE-2026-3288 & CVE-2026-24512: Ingress-nginx configuration injection vulnerabilities for Kubernetes Malware detection with Sysdig Security briefing: February 2026 Leveling up Kubernetes Posture: From baselines to risk-aware admission Eliminating runtime blind spots: How CleanStart and Sysdig build continuous trust across the container lifecycle LLMjacking: From Emerging Threat to Black Market Reality Real risks live at runtime: Why CISOs must care about deep telemetry in 2026 Sysdig named a Leader in the Forrester Wave™: Cloud Native Application Protection Solutions, Q1 2026 AI-assisted cloud intrusion achieves admin access in 8 minutes Security briefing: January 2026 Securing GPU-accelerated AI workloads in Oracle Kubernetes Engine Bringing OSS runtime security to AWS: Falco integration with AWS Security Hub CSPM Our customers have spoken: Sysdig rated a Strong Performer in Gartner® Voice of the Customer for Cloud-Native Application Protection Platforms Protecting sensitive business data in preparation for the organization's Gen AI VoidLink threat analysis: Sysdig discovers C2-compiled kernel rootkits AI is still a workload: A practical guide to securing AI workloads How threat actors are using self-hosted GitHub Actions runners as backdoors How Sysdig Sage delivers AI-powered, real-world vulnerability management Security briefing: December 2025 Top 10 ways to get breached in 2026 EtherRAT dissected: How a React2Shell implant delivers 5 payloads through blockchain C2 Introducing runtime file integrity monitoring and response with Sysdig FIM How to detect multi-stage attacks with runtime behavioral analytics EtherRAT: DPRK uses novel Ethereum implant in React2Shell attacks Detecting React2Shell: The maximum-severity RCE vulnerability affecting React Server Components and Next.js The rise of AI agents: How autonomous AI Is transforming cloud security Kubernetes 1.35 - New security features The Urgency of Securing AI Workloads for CISOs Security briefing: November 2025 Quantum and the cloud: Science fiction turned security strategy Cloud security, the right way: What the industry should demand (and why "good enough" isn't) Return of the Shai-Hulud worm affects over 25,000 GitHub repositories Detecting CVE-2024-1086: The decade-old Linux kernel vulnerability that’s being actively exploited in ransomware campaigns What’s old is new again: How to demystify AI security with AIBOMs Securing Kubernetes with agentic cloud security How agentic cloud security reduces real risks Hunting reverse shells: How the Sysdig Threat Research Team builds smarter detection rules Shifting left with AI and MCP: Sysdig + Amazon Q Developer How Falco and Stratoshark close the gap between open source runtime detection and deep forensic analysis Investigating security issues with ChatGPT and the GitHub MCP server New runc vulnerabilities allow container escape: CVE-2025-31133, CVE-2025-52565, CVE-2025-52881 Harden your LLM security with OWASP Security briefing: October 2025 How agentic AI is changing cloud security Kubernetes Incident Response: Detect, investigate, and contain in under 10 minutes Sysdig recognized as a Cloud Security Leader in Latio Tech Cloud Security Market Report AI echolocation of cloud risks using Sysdig & Snyk MCP servers Sysdig MCP Server: Bridging AI and cloud security insights Understanding CVE-2025-49844: “RediShell” Critical Remote Code Execution in Redis How Sysdig secures your containers and Kubernetes Sysdig Security Briefing: September 2025 Cloud security, the right way: The 3 pillars of real-time defense Open source spotlight: Bringing web application security to Falco with Falcoya's Nginx plugin Malicious NPM packages: Are you exposed? AI for SOC teams: 5 cloud security prompts to start your day with Sysdig Sage™ Shai-Hulud: The novel self-replicating worm infecting hundreds of NPM packages ZynorRAT technical analysis: Reverse engineering a novel, Turkish Go-based RAT Modern vulnerability management, built for the cloud Build your AWS incident response playbook with open source tools 2025 Gartner® CNAPP Market Guide: Runtime visibility is no longer optional Threat hunting with Sysdig: Uncovering “IngressNightmare” Open source spotlight: From alerts to action with AI-powered Falco Vanguard From triage to action: How Sysdig’s agentic cloud security platform slashes noise and accelerates remediation The vision comes to life: Agentic cloud security with Sysdig Sage™ Data security findings: A technical deep dive Connecting runtime to source: Sysdig and Semgrep integration Fix what matters, faster: How Sysdig and Semgrep are unifying security without silos – from code to runtime Defending sensitive data with Sysdig Secure Redefining cloud security, the right way Join the movement: The Sysdig Open Source Community is live A smarter, safer cloud in the age of AI Unifying detection and response: Sysdig + Cortex XSOAR for security at cloud speed The future of security is open, and it needs a unified hub: The Sysdig Open Source Community is here CVE-2025-53104: Command injection via GitHub Actions workflow in gluestack-ui Why MCP server security is critical for AI-driven enterprises What’s new in Sysdig — June 2025 AI-powered CNAPP with Sysdig Sage™ Revolutionizing Cybersecurity Search with Sysdig Sage™ Sysdig Threat Bulletin: Iranian Cyber Threats The end of the prioritization-only era: Vulnerability management needs action Dangerous by default: Insecure GitHub Actions found in MITRE, Splunk, and other open source repositories
How to run rootless containers
Matt Kim · 2026-02-10 · via Sysdig Blog

Using rootless containers, or unprivileged containers, is one of the most effective container security best practices.

The thing is, you don’t need to run processes as root the vast majority of the time. On a bare-metal server, most services don’t run as root. So why is it that 80% of containers run as root?

The root of all evil (pun intended) comes from Docker’s defaults. If you don’t specify otherwise, Docker will run a container’s processes as UID 0, the root user. Developers became used to this: not providing unprivileged versions of their images, and other container runtimes maintained this behaviour to maintain compatibility.

Luckily, running unprivileged has gotten easier over time.

In this article, we will:

  • Cover the risks of running as root.
  • Discover how to adapt an image to run as an unprivileged user.
  • Leverage User Namespaces to isolate privileged containers.

The dangers of running as root

In summary, we are making things easier for attackers if a container gets compromised.

When that happens, attackers will have root access — meaning full control — inside the container. This allows them to:

  • Run processes and modify binaries.
  • Find credentials in files you thought were secured, enabling lateral movement.

And overall, it’s easier for them to exploit vulnerabilities and break out into the host, as you can see in these blog posts:

That’s why running containers as rootless is such a good practice. It allows us to further isolate our workloads, minimizing damage caused by a compromised container.

Tradeoffs of running rootless

Although it’s getting easier over time, running containers as unprivileged is not straightforward.

You need to adapt your images so processes can run unprivileged, which involves changing ports and reviewing file permissions. We’ll cover this process in the next section.

You will also lose low-level access to some resources. Security probes, such as the Sysdig Agent, need this access to fetch detailed context about what’s running on your host. It’s OK to run these workloads as root, as they are a tiny fraction of your containers, and it’s easy to implement extra controls for them.

You can also use User Namespaces and Capabilities to run containers with limited privileges; we’ll cover how below. The tradeoff for these features is that processes are still somewhat privileged, especially if you are overly permissive with the CAP_SYS_ADMIN and CAP_NET_ADMIN capabilities. We covered this topic in our article “How to detect the containers’ escape capabilities with Falco.”

Prepare your image to be rootless

In theory, preparing your image to run unprivileged is simple:

  1. Only use ports above 1024.
  2. Review file permissions so unprivileged users can access what they need.

In practice, this is not always as easy to implement, so let’s learn with a real-world
example. We’ll use the nginx-unprivileged image, as its code is available and has
ample documentation.

The nginx-unprivileged image achieves rootlessness by making several changes on
the /etc/nginx/conf.d/default.conf config file:

# implement changes required to run NGINX as an unprivileged user
RUN sed -i 's,listen       80;,listen       8080;,' /etc/nginx/conf.d/default.conf \
    && sed -i '/user  nginx;/d' /etc/nginx/nginx.conf \
    && sed -i 's,\(/var\)\{0\,1\}/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf \
    && sed -i "/^http {/a \    proxy_temp_path /tmp/proxy_temp;\n    client_body_temp_path /tmp/client_temp;\n    fastcgi_temp_path /tmp/fastcgi_temp;\n    uwsgi_temp_path /tmp/uwsgi_temp;\n    scgi_temp_path /tmp/scgi_temp;\n" /etc/nginx/nginx.conf \
    && sed -i 's,PIDFILE=${PIDFILE:-/run/nginx.pid},PIDFILE=${PIDFILE:-/tmp/nginx.pid},' /etc/init.d/nginx \

Let’s review them.

First, the 8080 port is set as the default since any user can listen on ports above 1024, but only a privileged user can listen on port 80.

sed -i 's,listen       80;,listen       8080;,' /etc/nginx/conf.d/default.conf

Then, you can properly map your ports in your container runtime:

docker run -p 8080:80 nginx-unprivileged

Next, ensure there are no user changes by removing the user directive:

&& sed -i '/user  nginx;/d' /etc/nginx/nginx.conf \

It continues by changing several folders to “tmp”, accessible to unprivileged users:

&& sed -i 's,\(/var\)\{0\,1\}/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf \
    && sed -i "/^http {/a \    proxy_temp_path /tmp/proxy_temp;\n    client_body_temp_path /tmp/client_temp;\n    fastcgi_temp_path /tmp/fastcgi_temp;\n    uwsgi_temp_path /tmp/uwsgi_temp;\n    scgi_temp_path /tmp/scgi_temp;\n" /etc/nginx/nginx.conf \
    && sed -i 's,PIDFILE=${PIDFILE:-/run/nginx.pid},PIDFILE=${PIDFILE:-/tmp/nginx.pid},' /etc/init.d/nginx \

The changed files are the PID files and temporary files.

Finally, it makes the configuration and cache folders writable by the user:

# nginx user must own the cache and etc directory to write cache and tweak the nginx config
    && chown -R $UID:0 /var/cache/nginx \
    && chmod -R g+w /var/cache/nginx \
    && chown -R $UID:0 /etc/nginx \
    && chmod -R g+w /etc/nginx

You may have already guessed that modifying an image to run unprivileged is easy, but only as long as the services inside the container are prepared for that effect. The NGINX server is highly parameterized and can change its behaviour from configuration files without modifying the source code.

Luckily, most software follows these principles. The trick is knowing the list of files that need to be moved to the /tmp directory.

Extra security tips related to root privileges

Preparing your image to run unprivileged is only the first step. You can further strengthen the security of your container with a few steps.

First, ensure your binaries are root-owned so an attacker can’t modify them if the container gets compromised. If your Dockerfile looks like this:

...
WORKDIR $APP_HOME
COPY --chown=app:app app-files/ /app
USER app
ENTRYPOINT /app/my-app-entrypoint.sh
Code language: JavaScript (javascript)

Drop the --chown=app:app flag for your binaries, or avoid RUN chown commands. Your user doesn’t need to own the binaries; they only need execute permissions.

Another tip: If possible, run your containers in read-only mode with an allowlist for the files that need read-write. Use the --readonly flag to mount the container’s volume as read-only, then use -v to list the files that can be modified:

$ docker run --read-only -v /tmp

For nginx-unprivileged, you would do something like this:

$ docker run -d -p 8080:80 --read-only -v $(pwd)/nginx-cache:/var/cache/nginx -v $(pwd)/nginx-pid:/var/run nginx-unprivileged

Lastly, if you need to run commands like apt during the build phase, you can use multi-stage builds to build as root, then run the main process as a regular user:

# This is the builder stage
FROM gcr.io/distroless/static-debian10 as builder
[…]
RUN apt-get [your apt and build commands here]
[…]
# Final stage, copy required artifacts from builder
FROM gcr.io/distroless/static-debian10 as builder
[…]
COPY --from=builder /file/to/copy
USER myuser
[…]

Check out our Top 20 Dockerfile best practices article for more tips on securing containers.

Capabilities and user namespaces

As mentioned earlier, some containers need to perform privileged operations, such as accessing the network stack directly or using ptrace.

Capabilities

The most secure way to allow this is to use Linux capabilities. You can use capabilities to grant specific privileges to a regular user.

You can configure this on Docker with the --cap-add flag:

$ docker run --cap-add=SYS_PTRACE […]

You can define capabilities for your Kubernetes Pods inside securityContext:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/hello-app:2.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

User namespaces

However, sometimes you don’t have the time to adapt a container image to run unprivileged or to use capabilities.

In these cases, you can use user namespaces to abstract the user running inside a container from the user executing the workload on the host. That way, you can run a process as root inside the container while it runs as a regular user on the host.

With user namespaces, if an attacker escapes the container, they won’t have special privileges on the host, limiting the damage they can cause.

To enable user namespaces in Docker, you need to configure the mappings in the /etc/subuid and /etc/subgid files. These steps are similar for other container runtimes, you will find links to their documentations right after this example.

For a given user with the following ids:

$ id testuser
uid=1001(testuser) gid=1001(testuser) groups=1001(testuser)

We could create a user namespace by adding an entry like this one to both /etc/subuid and /etc/subgid:

testuser:231072:65536

This namespace reserves 65536 user ids, starting with 231072. Within this range, all user ids will be mapped to testuser, with 231072 mapped to UID 0 inside the namespace.

Then you would start dockerd with the --userns-remap flag to specify the default host user for containers to run as.

$ dockerd --userns-remap="testuser:testuser"

Most container runtimes support user namespaces in Linux, including Podman, CRI-O, runc, and containerd.

Kubernetes supports user namespaces for Pods. You can enable this feature by setting hostUsers: false in a Pod’s deployment yaml:

apiVersion: v1
kind: Pod
metadata:
  name: userns
spec:
  hostUsers: false
[…]

Support for user namespaces in Kubernetes continues to improve. For example, an alpha enhancement in Kubernetes 1.35 decouples user namespaces from access to the host network stack.

Conclusion

By using rootless containers, we can create a line of defense in case one of our containers is compromised.

Running unprivileged has become easier over time, and we can use tools like capabilities or user namespaces when rootless is not an option.

There’s never been a better time to try this out.

Get more details in our Container security whitepaper!