Skip to content

fix: harden sandbox image — remove gcc/netcat, add process limits, drop capabilities#830

Merged
cv merged 9 commits intoNVIDIA:mainfrom
BenediktSchackenberg:fix/sandbox-image-hardening
Mar 25, 2026
Merged

fix: harden sandbox image — remove gcc/netcat, add process limits, drop capabilities#830
cv merged 9 commits intoNVIDIA:mainfrom
BenediktSchackenberg:fix/sandbox-image-hardening

Conversation

@BenediktSchackenberg
Copy link
Contributor

@BenediktSchackenberg BenediktSchackenberg commented Mar 24, 2026

Hardens the sandbox image: removes gcc/g++/make/netcat from runtime, adds ulimit -u 512 for fork bomb protection, adds docs for cap-drop=ALL. Fixes #807, #808, #809.

Note: #797 (capability dropping) is documented in the hardening guide but not enforced at container level — that needs a runtime/compose-level fix.

AI-assisted: Built with Claude, reviewed by human.

Summary by CodeRabbit

  • Documentation

    • Added a sandbox hardening guide with deployment examples for image optimization, process limits, capability drops, read-only filesystems, and tmpfs usage.
  • Chores

    • Reduced runtime image contents by removing build and network tooling.
    • Enforced a 512-process limit at container startup.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Runtime image now purges build toolchain packages and network probing utilities, runs apt autoremove and clears apt caches. A startup script was updated to set process ulimits early. New documentation describes the sandbox hardening, ulimit guidance, and recommended runtime capability settings.

Changes

Cohort / File(s) Summary
Container runtime
Dockerfile
Runtime stage removes build toolchain packages (gcc, g++, cpp, make and versioned variants) and network probing tools (netcat-openbsd, netcat-traditional, ncat); suppresses apt removal errors, runs apt-get autoremove --purge -y, and clears /var/lib/apt/lists/*. No ENTRYPOINT/CMD changes in this diff.
Startup script
scripts/nemoclaw-start.sh
Adds early process-limit hardening via ulimit -Hu 512 and ulimit -Su 512 (errors suppressed with `
Documentation
docs/deployment/sandbox-hardening.md
Adds a new “Sandbox Image Hardening” doc describing removal of build/tooling from the runtime image, recommending multi-stage builds for compilation, documenting process limits (ulimit -u 512) and runtime capability/drop guidance with Docker and Docker Compose examples.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hide the compilers under straw and hay,

I hush the netcats so they cannot play.
I tuck limits in place to keep things light,
A quieter burrow through day and night. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main changes: removing gcc/netcat, adding process limits, and documenting capability dropping in the sandbox image.
Linked Issues check ✅ Passed The PR successfully addresses issue #807 by removing gcc, g++, make, and build-essential from the runtime image, and adds process limits and capability documentation as additional hardening measures.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the security hardening objectives: Dockerfile removes build tools, scripts add process limits, and documentation explains the hardening approach.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens the NemoClaw sandbox runtime by reducing available tooling, adding process-count limits to mitigate fork-bombs, and documenting capability-dropping guidance for container runtimes (fixes #807, #808, #809; addresses #797).

Changes:

  • Adds an nproc (max processes) limit via ulimit in the startup script and container entrypoint.
  • Removes/purges compiler toolchain and netcat variants from the runtime image.
  • Adds deployment documentation for sandbox hardening (capabilities, ulimits, read-only FS, etc.).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
scripts/nemoclaw-start.sh Applies ulimit -u 512 during startup to reduce fork-bomb risk.
docs/deployment/sandbox-hardening.md Documents image hardening steps and secure runtime flags (cap-drop, ulimits, etc.).
Dockerfile Purges risky tooling from runtime and enforces process limits in ENTRYPOINT.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

set -euo pipefail

# Harden: limit process count to prevent fork bombs (ref: #809)
ulimit -u 512 2>/dev/null || true
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ulimit -u 512 sets the soft limit by default; an untrusted process can often raise its soft limit back up to the inherited hard limit (potentially unlimited), bypassing the fork-bomb mitigation. Consider setting the hard limit as well (and then the soft limit) so the cap can’t be increased within the container.

Suggested change
ulimit -u 512 2>/dev/null || true
ulimit -H -u 512 2>/dev/null || true
ulimit -S -u 512 2>/dev/null || true

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — now setting both hard and soft limits.

Dockerfile Outdated

ENTRYPOINT ["/bin/bash"]
# Enforce process limits to mitigate fork bombs (#809)
ENTRYPOINT ["/bin/bash", "-c", "ulimit -u 512 2>/dev/null; exec \"$@\"", "--"]
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as the startup script: ulimit -u 512 typically only constrains the soft limit, which can be raised up to the hard limit by the running process. To make this mitigation effective, set the hard limit too (and then set soft to match) inside the ENTRYPOINT wrapper.

Suggested change
ENTRYPOINT ["/bin/bash", "-c", "ulimit -u 512 2>/dev/null; exec \"$@\"", "--"]
ENTRYPOINT ["/bin/bash", "-c", "ulimit -Hu 512 2>/dev/null; ulimit -Su 512 2>/dev/null; exec \"$@\"", "--"]

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the same commit.

Comment on lines +31 to +35
docker run --rm \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--ulimit nproc=512:512 \
nemoclaw-sandbox
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example re-adds NET_BIND_SERVICE, but the documented/default UI port in this repo context is 18789 (>1024), which doesn’t require binding privileged ports. Recommending an extra capability when it may not be needed weakens the hardening guidance—either remove --cap-add=NET_BIND_SERVICE from the baseline example or annotate it as optional/only required when binding to ports <1024.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed — port 18789 doesn't need it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
docs/deployment/sandbox-hardening.md (4)

38-57: Add an introductory sentence under this H3 section before the code block.

### Docker Compose Example currently starts with YAML immediately.

As per coding guidelines, "Sections use H2 and H3, each starting with an introductory sentence."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/deployment/sandbox-hardening.md` around lines 38 - 57, The "Docker
Compose Example" H3 section currently jumps straight into the YAML block; add a
brief introductory sentence immediately under the "### Docker Compose Example"
header (before the fenced code block) that explains what the example shows
(e.g., that it demonstrates a hardened Docker Compose service definition for the
nemoclaw-sandbox service), so update the section containing the heading "Docker
Compose Example" to insert that one-line intro above the YAML code block.

59-62: Replace the blockquote note with a MyST admonition.

Use :::{note} instead of > **Note:** .... Also, the bold emphasis here is an LLM-pattern style issue. LLM pattern detected.

As per coding guidelines, "Use MyST admonitions (:::{tip}, :::{note}, :::{warning}) for callouts, not bold text or blockquotes." and "Unnecessary bold on routine instructions ... should be flagged. LLM pattern detected."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/deployment/sandbox-hardening.md` around lines 59 - 62, Replace the
blockquote that starts with "> **Note:** The `Dockerfile` itself cannot enforce
`--cap-drop` ..." with a MyST admonition using the :::{note} ... ::: syntax;
remove the bold markup and rewrite the same sentence inside the admonition so it
uses MyST callout formatting (use :::{note} before the text and ::: after)
instead of the LLM-style "> **Note:**" blockquote.

64-69: Add a final Next Steps section with related links.

The page currently ends at References and is missing the required closing navigation section.

As per coding guidelines, "A 'Next Steps' section at the bottom links to related pages."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/deployment/sandbox-hardening.md` around lines 64 - 69, Add a final "Next
Steps" section after the existing "References" heading that provides navigation
to related documentation; create a level-2 heading "Next Steps" and include a
short bulleted list of links to relevant pages (e.g., deployment hardening,
sandbox configuration, troubleshooting or related issues) using the same
markdown link style as the rest of the file so the page ends with the required
closing navigation section.

3-24: Use one sentence per source line in prose paragraphs.

Several sentences are wrapped across multiple source lines, which makes diffs noisier in docs edits.

As per coding guidelines, "One sentence per line in source (makes diffs readable)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/deployment/sandbox-hardening.md` around lines 3 - 24, The prose in
docs/deployment/sandbox-hardening.md currently wraps multiple sentences per
source line (notably in the "Removed Unnecessary Tools" and "Process Limits"
paragraphs and lines mentioning ENTRYPOINT, `ulimit -u 512`, and
`nemoclaw-start.sh`), which makes diffs noisy; rewrite the paragraphs so each
sentence occupies its own source line—split long lines into separate lines at
sentence boundaries, preserving existing wording and references (e.g., `gcc`,
`g++`, `make`, `netcat`, `builder`, `ENTRYPOINT`, `--ulimit nproc=512:512`) to
comply with the "one sentence per line" guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Around line 23-25: The shell `|| true` at the end of the long `&&` chain makes
the whole chain succeed even if earlier commands (like `apt-get update` or
`apt-get install`) fail; restrict the error masking to only the remove step by
grouping that command and its redirection and `|| true` so it doesn't apply to
previous commands. Locate the `apt-get remove --purge -y gcc ...
netcat-traditional ncat 2>/dev/null || true` fragment in the Dockerfile and
change it to a grouped form (e.g. wrap the remove command in parentheses or
braces with its `2>/dev/null || true`) so only that remove command is tolerant
of failure while the earlier `apt-get update`/`apt-get install` steps still
cause the build to fail on error.

In `@docs/deployment/sandbox-hardening.md`:
- Around line 30-36: The code block showing the docker run example is using a
```bash fence and lacks prompt prefixes; change the fence to use the `console`
language tag and add a leading `$ ` prompt to each CLI line (the docker
invocation lines including `docker run --rm \`, `--cap-drop=ALL \`,
`--cap-add=NET_BIND_SERVICE \`, `--ulimit nproc=512:512 \`, and
`nemoclaw-sandbox`) so the snippet follows the CLI guideline of `console` with
`$` prompts.
- Around line 1-2: Add canonical frontmatter and an SPDX license header to this
new docs page: wrap the existing top-level heading "# Sandbox Image Hardening"
with YAML frontmatter that includes title, description, keywords, topics, tags,
content type, difficulty, audience, and status fields, and then insert the SPDX
license header immediately after the closing frontmatter marker; ensure the SPDX
header uses the project's standard identifier (e.g., "SPDX-License-Identifier:
<LICENSE>") and that the frontmatter values accurately describe the "Sandbox
Image Hardening" page.

---

Nitpick comments:
In `@docs/deployment/sandbox-hardening.md`:
- Around line 38-57: The "Docker Compose Example" H3 section currently jumps
straight into the YAML block; add a brief introductory sentence immediately
under the "### Docker Compose Example" header (before the fenced code block)
that explains what the example shows (e.g., that it demonstrates a hardened
Docker Compose service definition for the nemoclaw-sandbox service), so update
the section containing the heading "Docker Compose Example" to insert that
one-line intro above the YAML code block.
- Around line 59-62: Replace the blockquote that starts with "> **Note:** The
`Dockerfile` itself cannot enforce `--cap-drop` ..." with a MyST admonition
using the :::{note} ... ::: syntax; remove the bold markup and rewrite the same
sentence inside the admonition so it uses MyST callout formatting (use :::{note}
before the text and ::: after) instead of the LLM-style "> **Note:**"
blockquote.
- Around line 64-69: Add a final "Next Steps" section after the existing
"References" heading that provides navigation to related documentation; create a
level-2 heading "Next Steps" and include a short bulleted list of links to
relevant pages (e.g., deployment hardening, sandbox configuration,
troubleshooting or related issues) using the same markdown link style as the
rest of the file so the page ends with the required closing navigation section.
- Around line 3-24: The prose in docs/deployment/sandbox-hardening.md currently
wraps multiple sentences per source line (notably in the "Removed Unnecessary
Tools" and "Process Limits" paragraphs and lines mentioning ENTRYPOINT, `ulimit
-u 512`, and `nemoclaw-start.sh`), which makes diffs noisy; rewrite the
paragraphs so each sentence occupies its own source line—split long lines into
separate lines at sentence boundaries, preserving existing wording and
references (e.g., `gcc`, `g++`, `make`, `netcat`, `builder`, `ENTRYPOINT`,
`--ulimit nproc=512:512`) to comply with the "one sentence per line" guideline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 34b06a27-121c-4a29-82a4-fba458cc626d

📥 Commits

Reviewing files that changed from the base of the PR and between b79b7e8 and 9427f6a.

📒 Files selected for processing (3)
  • Dockerfile
  • docs/deployment/sandbox-hardening.md
  • scripts/nemoclaw-start.sh

@BenediktSchackenberg
Copy link
Contributor Author

[Comment 2984015992] Good catch! Updated to set both hard and soft limits (ulimit -Hu 512 && ulimit -Su 512) so the agent can't raise it back. Fixed in 1ca5c43.

@BenediktSchackenberg
Copy link
Contributor Author

[Comment 2984016021] Fixed — same approach here, ENTRYPOINT now sets hard + soft limit.

@BenediktSchackenberg
Copy link
Contributor Author

[Comment 2984016041] Right, restored CMD ["/bin/bash"] so interactive docker run -it still works. The ENTRYPOINT uses exec so it passes through to bash when no args are given.

@BenediktSchackenberg
Copy link
Contributor Author

[Comment 2984016064] You're right, port 18789 doesn't need NET_BIND_SERVICE. Removed from the example.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Dockerfile (1)

172-174: ENTRYPOINT pattern is correct; note && chaining behavior.

The Docker ENTRYPOINT/CMD pattern with "--" as $0 placeholder is valid. The ; before exec ensures the container always starts.

One consideration: using && between the two ulimit commands means if the hard limit fails, the soft limit won't be attempted. This is likely intentional (soft limit alone offers no protection since it can be raised), but if you want both to be attempted independently, consider using ; instead:

-ENTRYPOINT ["/bin/bash", "-c", "ulimit -Hu 512 2>/dev/null && ulimit -Su 512 2>/dev/null; exec \"$@\"", "--"]
+ENTRYPOINT ["/bin/bash", "-c", "ulimit -Hu 512 2>/dev/null; ulimit -Su 512 2>/dev/null; exec \"$@\"", "--"]

Additionally, the silent suppression via 2>/dev/null means operators won't know if process limits fail to apply. For production hardening, consider logging a warning or using a health check to verify limits are in effect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 172 - 174, The ENTRYPOINT uses `ulimit -Hu 512 &&
ulimit -Su 512 2>/dev/null` so the soft limit is skipped if the hard limit fails
and stderr is suppressed; update the `ENTRYPOINT` invocation (the `ENTRYPOINT`,
`CMD`, `ulimit`, `exec`, and `"--"` sequence) to run both `ulimit` calls
independently (use `;` between them) and stop silencing failures (remove or
redirect `2>/dev/null`) or add a visible warning/logging mechanism so operators
can see if limits failed to apply.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dockerfile`:
- Around line 172-174: The ENTRYPOINT uses `ulimit -Hu 512 && ulimit -Su 512
2>/dev/null` so the soft limit is skipped if the hard limit fails and stderr is
suppressed; update the `ENTRYPOINT` invocation (the `ENTRYPOINT`, `CMD`,
`ulimit`, `exec`, and `"--"` sequence) to run both `ulimit` calls independently
(use `;` between them) and stop silencing failures (remove or redirect
`2>/dev/null`) or add a visible warning/logging mechanism so operators can see
if limits failed to apply.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8aef0119-f91a-42a3-8c49-38e99d3835b8

📥 Commits

Reviewing files that changed from the base of the PR and between 1ca5c43 and 856adc5.

📒 Files selected for processing (2)
  • Dockerfile
  • docs/deployment/sandbox-hardening.md
✅ Files skipped from review due to trivial changes (1)
  • docs/deployment/sandbox-hardening.md

@h-network
Copy link

This does not address #797 as the writer claims

@BenediktSchackenberg
Copy link
Contributor Author

You're right — updated the PR description. #797 needs a runtime-level fix (compose/docker flags), not just docs. Removed it from the Fixes list.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Dockerfile (1)

189-193: ⚠️ Potential issue | 🔴 Critical

Config hash file is no longer generated, breaking startup and e2e tests.

The build-time .config-hash generation was removed, but scripts/nemoclaw-start.sh still calls verify_config_integrity() which expects /sandbox/.openclaw/.config-hash to exist. In root mode (line 209), this is called without error handling, causing the container to refuse startup with "[SECURITY] Config hash file missing".

Additionally, the e2e test at test/e2e-gateway-isolation.sh:98-102 explicitly validates that the hash file exists and matches openclaw.json.

Either restore the hash generation or update verify_config_integrity() and the e2e tests to handle the missing file.

Proposed fix — restore config hash generation

Add after line 193 (after locking openclaw.json permissions):

     && chmod 444 /sandbox/.openclaw/openclaw.json
+
+# Pin config hash for runtime integrity verification (ref: nemoclaw-start.sh)
+RUN cd /sandbox/.openclaw \
+    && sha256sum openclaw.json > .config-hash \
+    && chmod 444 .config-hash
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 189 - 193, The container startup fails because the
build step that generated /sandbox/.openclaw/.config-hash was removed but
scripts/nemoclaw-start.sh still calls verify_config_integrity() (which expects
.config-hash) and e2e tests in test/e2e-gateway-isolation.sh assert the file
exists; restore the missing .config-hash generation in the Dockerfile
immediately after locking openclaw.json (after the chmod lines) by computing a
stable hash (e.g., SHA256) of /sandbox/.openclaw/openclaw.json and writing it to
/sandbox/.openclaw/.config-hash with appropriate ownership/permissions, or
alternatively update verify_config_integrity() and the e2e test to tolerate a
missing .config-hash by implementing fallback behavior — reference
verify_config_integrity(), scripts/nemoclaw-start.sh, .config-hash,
openclaw.json, and test/e2e-gateway-isolation.sh when applying the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@Dockerfile`:
- Around line 189-193: The container startup fails because the build step that
generated /sandbox/.openclaw/.config-hash was removed but
scripts/nemoclaw-start.sh still calls verify_config_integrity() (which expects
.config-hash) and e2e tests in test/e2e-gateway-isolation.sh assert the file
exists; restore the missing .config-hash generation in the Dockerfile
immediately after locking openclaw.json (after the chmod lines) by computing a
stable hash (e.g., SHA256) of /sandbox/.openclaw/openclaw.json and writing it to
/sandbox/.openclaw/.config-hash with appropriate ownership/permissions, or
alternatively update verify_config_integrity() and the e2e test to tolerate a
missing .config-hash by implementing fallback behavior — reference
verify_config_integrity(), scripts/nemoclaw-start.sh, .config-hash,
openclaw.json, and test/e2e-gateway-isolation.sh when applying the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8d421c9f-e655-45b6-8b79-63c21ceadd5f

📥 Commits

Reviewing files that changed from the base of the PR and between 856adc5 and 5b4c659.

📒 Files selected for processing (3)
  • Dockerfile
  • docs/deployment/sandbox-hardening.md
  • scripts/nemoclaw-start.sh
✅ Files skipped from review due to trivial changes (1)
  • docs/deployment/sandbox-hardening.md

@cv
Copy link
Contributor

cv commented Mar 25, 2026

@BenediktSchackenberg sorry I only saw your comment on #917 a second after merging the PR. I'd still like to get these changes in, would you mind resolving the conflicts, please?

…es, add process limits

- Remove gcc, g++, make, netcat from runtime image to reduce attack surface
- Add ulimit -u 512 in ENTRYPOINT and start script to prevent fork bombs
- Add deployment doc with Docker Compose example for dropping capabilities
- Document security hardening measures

Fixes NVIDIA#807, NVIDIA#808, NVIDIA#809. Addresses NVIDIA#797.
…SERVICE

- Set both hard and soft ulimit in nemoclaw-start.sh and Dockerfile
  ENTRYPOINT to prevent agent from raising soft limit back up
- Restore CMD ["/bin/bash"] so 'docker run -it' still drops into a shell
- Remove --cap-add=NET_BIND_SERVICE from docs example since port 18789 > 1024
Address CodeRabbit review comments:
- Dockerfile: wrap apt-get remove in subshell so || true only applies to the
  remove command, not the entire RUN chain
- docs/sandbox-hardening.md: add YAML frontmatter and SPDX header
- docs/sandbox-hardening.md: use console fence with $ prompt for CLI examples
@BenediktSchackenberg BenediktSchackenberg force-pushed the fix/sandbox-image-hardening branch from 5b4c659 to 76dc5dc Compare March 25, 2026 21:16
@BenediktSchackenberg
Copy link
Contributor Author

BenediktSchackenberg commented Mar 25, 2026

Done — rebased on main and resolved the conflicts from #917. Both our changes (gcc/netcat removal, ulimit hardening) and the capsh capability-dropping from #917 are preserved. Ready for review! @cv

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 18-20: The ulimit calls in scripts/nemoclaw-start.sh currently
suppress errors (the `2>/dev/null || true`), so replace that silent suppression
with explicit failure and verification: run `ulimit -Hu 512` and `ulimit -Su
512` without redirection, check their exit status and/or read back `ulimit -Hu`
and `ulimit -Su` to ensure they report >=512, and if either call fails or
returns a lower value print a clear error to stderr and exit non‑zero so the
ENTRYPOINT fails loudly; update the script around the `ulimit -Hu` and `ulimit
-Su` lines to perform these checks and exit on failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 171b136c-99a4-4537-8fd3-73b2e420e144

📥 Commits

Reviewing files that changed from the base of the PR and between 5b4c659 and 76dc5dc.

📒 Files selected for processing (3)
  • Dockerfile
  • docs/deployment/sandbox-hardening.md
  • scripts/nemoclaw-start.sh
✅ Files skipped from review due to trivial changes (1)
  • docs/deployment/sandbox-hardening.md

Remove silent error suppression (2>/dev/null || true) so the entrypoint
exits non-zero if ulimit fails, preventing the container from running
without fork-bomb protection.
@BenediktSchackenberg BenediktSchackenberg force-pushed the fix/sandbox-image-hardening branch from 1f7f1c5 to d102f50 Compare March 25, 2026 21:30
cv added 2 commits March 25, 2026 16:00
@cv cv force-pushed the fix/sandbox-image-hardening branch from d0a13b3 to c2d0c5f Compare March 25, 2026 23:30
@cv cv merged commit 2e0066f into NVIDIA:main Mar 25, 2026
1 check passed
cjagwani added a commit that referenced this pull request Mar 26, 2026
…test

The gateway isolation E2E test sourced the first 21 lines of
nemoclaw-start to capture the PATH export. After #830 added ulimit
lines, the PATH export moved to line 30 and the test broke.

Replace head -21 with sed -n "1,/^export PATH=/p" so the test
dynamically finds the PATH export regardless of line number.
cjagwani added a commit that referenced this pull request Mar 26, 2026
The gateway isolation test previously sourced partial lines of the
entrypoint script to check PATH. This broke whenever the preamble
changed (e.g., #830 added ulimit lines). The grep fix on main is
also fragile since it sources a single line without preamble context.

Replace with a static file content check: verify the entrypoint
contains exactly one PATH export with the expected locked-down value.
This tests the security property directly without depending on line
numbers or partial script execution.
@BenediktSchackenberg BenediktSchackenberg deleted the fix/sandbox-image-hardening branch March 26, 2026 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY] gcc available in sandbox image — unnecessary attack surface

4 participants