Skip to content

fix(security): validate UPSTREAM_DNS before shell interpolation#1141

Open
fdzdev wants to merge 1 commit intoNVIDIA:mainfrom
fdzdev:fix/coredns-dns-injection
Open

fix(security): validate UPSTREAM_DNS before shell interpolation#1141
fdzdev wants to merge 1 commit intoNVIDIA:mainfrom
fdzdev:fix/coredns-dns-injection

Conversation

@fdzdev
Copy link
Copy Markdown
Contributor

@fdzdev fdzdev commented Mar 31, 2026

Summary

  • Add IPv4 regex validation for UPSTREAM_DNS before it is interpolated into the docker exec kubectl patch command (CWE-78, NVBUG 6009988)
  • Without validation, a malicious resolv.conf entry could inject shell metacharacters into the kubectl patch JSON payload
  • Rejects anything that isn't a valid IPv4 dotted-quad, aborting with a clear error

Test plan

  • fix-coredns.sh with valid DNS (e.g. 8.8.8.8) — patches CoreDNS normally
  • fix-coredns.sh with no resolvable DNS — falls back to 8.8.8.8, passes validation
  • Simulated bad UPSTREAM_DNS='"; rm -rf /' — rejected with error, no execution

Summary by CodeRabbit

  • Chores
    • Added validation for DNS upstream settings to prevent invalid values from being applied.
    • Added a precondition check for a required tooling dependency; the script now fails fast with a clear error if it's missing.
    • Improved how DNS configuration is constructed and applied to reduce risk of malformed updates and restarts.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 80661cc5-4d75-4624-8b48-34fa75495a2e

📥 Commits

Reviewing files that changed from the base of the PR and between 352ce80 and d681791.

📒 Files selected for processing (1)
  • scripts/fix-coredns.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/fix-coredns.sh

📝 Walkthrough

Walkthrough

Validate UPSTREAM_DNS against a restricted character set, require jq to be installed, build the CoreDNS Corefile via a heredoc and JSON-escape it with jq, then pass the resulting payload to kubectl patch and restart CoreDNS.

Changes

Cohort / File(s) Summary
CoreDNS patch script
scripts/fix-coredns.sh
Added input validation for UPSTREAM_DNS (restricted charset), added a precondition check that jq is installed, switched Corefile construction to a heredoc and used jq to JSON-escape the Corefile into PATCH_JSON before calling kubectl patch; retains existing restart flow.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Script as "fix-coredns.sh"
    participant jq
    participant kubectl
    participant K8sAPI as "Kubernetes API"

    User->>Script: invoke with UPSTREAM_DNS
    Script->>Script: validate UPSTREAM_DNS (charset)
    alt invalid
        Script-->>User: exit 1 (invalid input)
    else valid
        Script->>jq: escape Corefile heredoc -> PATCH_JSON
        jq-->>Script: PATCH_JSON
        Script->>kubectl: kubectl patch --patch PATCH_JSON
        kubectl->>K8sAPI: PATCH request
        K8sAPI-->>kubectl: 200 OK
        kubectl-->>Script: patch applied
        Script->>kubectl: rollout restart deployment/coredns
        kubectl->>K8sAPI: restart request
        K8sAPI-->>kubectl: restart accepted
        kubectl-->>Script: restart triggered
        Script-->>User: exit 0
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nudge the Corefile with a careful hop,
Checking each byte before I stop,
jq helps me quote with tidy grace,
No rogue characters find their place,
CoreDNS wakes, the cluster sings—hip hop hooray! 🎶

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main security fix: validating UPSTREAM_DNS before shell interpolation to prevent injection attacks.
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
Copy Markdown
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/fix-coredns.sh`:
- Line 70: The current if condition that tests UPSTREAM_DNS uses a permissive
regex and accepts invalid IPv4 addresses; change the validation in the if block
that references UPSTREAM_DNS so it enforces each octet is 0–255 (i.e., replace
the simple dot-number regex with a strict per-octet check that only matches
0–255 for all four octets) or alternatively call a reliable validator (e.g.,
POSIX utility or a short python/ipaddress check) to ensure UPSTREAM_DNS is a
valid IPv4 before proceeding to patch CoreDNS.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a616607c-2d46-4ca2-8036-8e356e17d6b8

📥 Commits

Reviewing files that changed from the base of the PR and between 0086886 and 352ce80.

📒 Files selected for processing (1)
  • scripts/fix-coredns.sh


# Validate UPSTREAM_DNS is a valid IPv4 address before shell-interpolating
# into the docker exec command (CWE-78, NVBUG 6009988).
if ! echo "$UPSTREAM_DNS" | grep -qE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

IPv4 validation on Line 70 is too permissive and accepts invalid addresses.

The current regex allows octets outside 0-255 (e.g., 999.1.1.1), so invalid DNS values can still be patched into CoreDNS and break resolution.

Proposed fix
-if ! echo "$UPSTREAM_DNS" | grep -qE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
+if ! printf '%s\n' "$UPSTREAM_DNS" | awk -F. '
+  NF != 4 { exit 1 }
+  {
+    for (i = 1; i <= 4; i++) {
+      if ($i !~ /^[0-9]+$/ || $i < 0 || $i > 255) exit 1
+    }
+  }
+  { exit 0 }
+'; then
   echo "ERROR: UPSTREAM_DNS='$UPSTREAM_DNS' is not a valid IPv4 address. Aborting."
   exit 1
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ! echo "$UPSTREAM_DNS" | grep -qE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
if ! printf '%s\n' "$UPSTREAM_DNS" | awk -F. '
NF != 4 { exit 1 }
{
for (i = 1; i <= 4; i++) {
if ($i !~ /^[0-9]+$/ || $i < 0 || $i > 255) exit 1
}
}
{ exit 0 }
'; then
echo "ERROR: UPSTREAM_DNS='$UPSTREAM_DNS' is not a valid IPv4 address. Aborting."
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/fix-coredns.sh` at line 70, The current if condition that tests
UPSTREAM_DNS uses a permissive regex and accepts invalid IPv4 addresses; change
the validation in the if block that references UPSTREAM_DNS so it enforces each
octet is 0–255 (i.e., replace the simple dot-number regex with a strict
per-octet check that only matches 0–255 for all four octets) or alternatively
call a reliable validator (e.g., POSIX utility or a short python/ipaddress
check) to ensure UPSTREAM_DNS is a valid IPv4 before proceeding to patch
CoreDNS.

Copy link
Copy Markdown
Contributor

@cv cv left a comment

Choose a reason for hiding this comment

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

Thanks for tackling this. I don't think we should merge the current approach as-is.

My main concern is that the fix constrains UPSTREAM_DNS to an IPv4 dotted-quad, which can reject valid upstreams unnecessarily (for example IPv6 nameservers). That makes the script less robust without really addressing the root issue.

I also think the security claim here is a bit overstated: the current code is definitely doing unsafe string construction, but the right fix is to stop interpolating the value into a shell/JSON blob directly, not to ban everything except IPv4.

I'd prefer a rework that constructs the kubectl patch payload safely (for example via a temp file / heredoc / proper escaping / jq-style JSON generation) and then validates the resolved upstream in a way that still permits legitimate values.

@wscurran wscurran added security Something isn't secure Docker Support for Docker containerization status: needs-info For issues/PRs that lack a description. (Signals to the author that more detail is required). labels Apr 1, 2026
Replace unsafe inline JSON string construction with jq-based payload
generation so UPSTREAM_DNS is never interpolated into a shell-constructed
JSON/string literal (CWE-78, NVBUG 6009988).

- Build Corefile as a heredoc, let jq handle all JSON escaping
- Defense-in-depth character-class check accepts IPv4, IPv6, and hostnames
- Require jq (standard on Ubuntu/Brev VMs) with explicit check

Made-with: Cursor
@fdzdev fdzdev force-pushed the fix/coredns-dns-injection branch from 352ce80 to d681791 Compare April 1, 2026 21:07
@fdzdev
Copy link
Copy Markdown
Contributor Author

fdzdev commented Apr 1, 2026

Reworked in d681791 — thanks for the feedback.

  • The kubectl patch payload is now built with jq -n --arg, so UPSTREAM_DNS is never interpolated into a shell-constructed JSON string. That's the actual injection fix.
  • The input validation is now a permissive character-class check (^[a-zA-Z0-9.:_-]+$) that accepts IPv4, IPv6, and hostnames — defense-in-depth only, not the security boundary.
  • The Corefile is a readable heredoc instead of the escaped one-liner.

Ready for re-review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docker Support for Docker containerization security Something isn't secure status: needs-info For issues/PRs that lack a description. (Signals to the author that more detail is required).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants