Skip to content

fix(security): defense-in-depth for env injection RCE (GHSA-h6hh-wqxc-5hw9)#41831

Open
subrata71 wants to merge 1 commit into
releasefrom
fix/rce-env-injection-ghsa-h6hh
Open

fix(security): defense-in-depth for env injection RCE (GHSA-h6hh-wqxc-5hw9)#41831
subrata71 wants to merge 1 commit into
releasefrom
fix/rce-env-injection-ghsa-h6hh

Conversation

@subrata71
Copy link
Copy Markdown
Collaborator

@subrata71 subrata71 commented May 20, 2026

Description

TL;DR: Replace Bash source of docker.env with a safe parser to prevent RCE via command injection, and add startup validation to detect/sanitize poisoned env files from previously exploited instances.

Background

GHSA-h6hh-wqxc-5hw9 (Critical, CVSS 9.1) describes an authenticated RCE where a super-admin injects $(...) command substitution into env values via PUT /api/v1/admin/env. The container's entrypoint.sh then sources docker.env with . "$ENV_PATH", which evaluates the payload on restart.

The core fix (escapeForShell() in EnvManagerCEImpl) shipped in v1.99. This PR adds defense-in-depth on top of that fix.

What changed

  1. New safe-env-loader.sh — provides three functions:

    • safe_source_env() — parses KEY=VALUE lines with a character-by-character state machine that handles single/double quoting without ever evaluating $(), backticks, or ${}
    • validate_env_file() — scans for dangerous shell metacharacters in unquoted value contexts
    • sanitize_env_file() — rewrites poisoned values with single-quote wrapping
  2. entrypoint.sh — replaced . "$ENV_PATH" and . "$TMP/pre-define.env" with safe_source_env(). Added validate_env_file || sanitize_env_file before loading.

  3. run-with-env.sh — same treatment as entrypoint.sh.

  4. 18 tests covering: quoting variants (single, double, embedded quotes), injection payloads ($(...), backticks, semicolons, ${IFS} trick from the actual PoC), validation detection, and sanitization.

Why defense-in-depth matters

  • Sink removal: Even if escapeForShell() were to regress, the source sink no longer exists — the safe parser treats all values as data.
  • Upgrade protection: Instances exploited before v1.99 still have poisoned docker.env on the persistent volume. The startup validator catches and sanitizes these on first run after upgrade.

Linear: APP-15243

Automation

/ok-to-test tags=""

🔍 Cypress test results

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Warning

Tests have not run on the HEAD 37ccaf0 yet


Wed, 20 May 2026 18:35:48 UTC

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened Docker deployment security with improved environment configuration handling, including validation and sanitization of external variables to prevent injection vulnerabilities.
  • Chores

    • Updated Docker entry point scripts to utilize safer environment loading mechanisms.
  • Tests

    • Added test suite for environment file processing and validation.

Review Change Stack

…-5hw9)

Replace Bash `source` of docker.env with a safe parser that handles
shell quoting without evaluating command substitution. Add startup
validation to detect and sanitize poisoned env files from previously
exploited instances.

- Add safe-env-loader.sh with safe_source_env(), validate_env_file(),
  and sanitize_env_file() functions
- Replace `. "$ENV_PATH"` in entrypoint.sh and run-with-env.sh
- Add 18 tests covering quoting variants, injection payloads, and
  the actual PoC pattern from the advisory

Defense-in-depth on top of existing escapeForShell() fix in v1.99.
@subrata71 subrata71 added the Security Issues related to information security within the product label May 20, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Walkthrough

This PR hardens Docker entrypoint environment loading against shell injection by replacing unsafe source with validated, character-by-character parsing. A new safe-env-loader.sh utility prevents command substitution and variable expansion. Two entrypoint scripts are updated to use it. Comprehensive tests verify injection prevention and value preservation.

Changes

Shell-Injection Defense for Environment Files

Layer / File(s) Summary
Safe environment loader implementation
deploy/docker/fs/opt/appsmith/safe-env-loader.sh
Dangerous unquoted pattern detection, character-by-character safe_source_env() parsing with quote/escape handling, validate_env_file() for dangerous pattern scanning, and sanitize_env_file() to rewrite values into quoted form. No source/. used; variables exported manually.
Entrypoint script integration
deploy/docker/fs/opt/appsmith/entrypoint.sh, deploy/docker/fs/opt/appsmith/run-with-env.sh
Both scripts now source safe-env-loader.sh and replace set -o allexport + dot-sourcing with validate_env_file(), sanitize_env_file(), and safe_source_env() calls to load docker.env and pre-define.env safely.
Test suite for safe env loader
deploy/docker/tests/test-safe-env-loader.sh
Test harness with setup/teardown, assertion helpers, and 150+ test cases exercising safe_source_env parsing (quoting, escaping, injection vectors), validate_env_file detection (command substitution, backticks), sanitize_env_file rewriting (dangerous values to quoted), environment export verification, and IFS-based regression payload tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🔐 Sourcing deemed unsafe, now parsed with care,
Character by character—no expansions dare,
Single quotes wrap the dangerous ones,
Dangerous patterns found and undone,
Tests one-fifty strong, injections banished! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: implementing defense-in-depth security for an RCE vulnerability (GHSA-h6hh-wqxc-5hw9).
Description check ✅ Passed The description comprehensively covers the security vulnerability, background, detailed changes, rationale, and includes links to tracking issues. All required sections are present and complete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rce-env-injection-ghsa-h6hh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@subrata71 subrata71 self-assigned this May 20, 2026
@subrata71 subrata71 requested a review from wyattwalter May 20, 2026 18:38
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.

🧹 Nitpick comments (2)
deploy/docker/tests/test-safe-env-loader.sh (1)

204-305: 💤 Low value

Consider adding a test for sanitizing values with embedded single quotes.

The test_sanitize_wraps_dangerous_values test verifies basic sanitization works, but doesn't exercise the embedded single-quote escaping logic (line 160 in the loader). A value like $(cmd'with'quotes) would exercise that path.

📋 Additional test case
+test_sanitize_handles_embedded_single_quotes() {
+  cat > "$TEST_TMPDIR/env" <<'EOF'
+APPSMITH_INSTANCE_NAME=$(cmd'arg)
+EOF
+  bash -c "
+    source '$LOADER_SCRIPT'
+    sanitize_env_file '$TEST_TMPDIR/env'
+  " 2>/dev/null
+  # After sanitization, loading should yield the literal value
+  local result
+  result=$(bash -c "
+    source '$LOADER_SCRIPT'
+    safe_source_env '$TEST_TMPDIR/env'
+    echo \"\$APPSMITH_INSTANCE_NAME\"
+  ")
+  assert_equals "$result" "\$(cmd'arg)" "sanitized value with embedded quote is literal"
+}

Then add to the run list:

 run_test test_ifs_trick_not_executed
+run_test test_sanitize_handles_embedded_single_quotes
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/docker/tests/test-safe-env-loader.sh` around lines 204 - 305, Add a
new test in deploy/docker/tests/test-safe-env-loader.sh that verifies
sanitize_env_file correctly escapes embedded single quotes inside dangerous
command-substitution values (e.g.,
APPSMITH_INSTANCE_NAME=$(cmd'with'quotes)Appsmith); in the test call
sanitize_env_file on a temp env file containing that value, then assert the
sanitized file passes validate_env_file and that safe_source_env exports the
variable with the single quotes preserved (use a new test name like
test_sanitize_handles_embedded_single_quotes and reference sanitize_env_file,
validate_env_file, and safe_source_env to locate the relevant logic).
deploy/docker/fs/opt/appsmith/safe-env-loader.sh (1)

12-14: 💤 Low value

Unused constant is dead code.

_DANGEROUS_UNQUOTED_PATTERN is declared but never referenced. The actual checks on lines 116 and 158 use inline patterns. Either remove the unused constant or refactor to use it consistently.

🧹 Remove dead code
-# Pattern matching shell metacharacters that indicate command injection
-# when found outside of single quotes in an env value.
-readonly _DANGEROUS_UNQUOTED_PATTERN='(\$\(|`|\$\(\(|\$\{[A-Za-z_])'
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/docker/fs/opt/appsmith/safe-env-loader.sh` around lines 12 - 14, The
script defines the readonly variable _DANGEROUS_UNQUOTED_PATTERN but never uses
it; update the env-value validation to either remove this dead constant or
reference it where the inline regexes are used (the two places that currently
embed patterns for command-injection detection in the env checks) so the single
source of truth is _DANGEROUS_UNQUOTED_PATTERN; specifically replace the inline
regex literals used in the env validation checks with the variable name or
delete the constant if you prefer to keep inline patterns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@deploy/docker/fs/opt/appsmith/safe-env-loader.sh`:
- Around line 12-14: The script defines the readonly variable
_DANGEROUS_UNQUOTED_PATTERN but never uses it; update the env-value validation
to either remove this dead constant or reference it where the inline regexes are
used (the two places that currently embed patterns for command-injection
detection in the env checks) so the single source of truth is
_DANGEROUS_UNQUOTED_PATTERN; specifically replace the inline regex literals used
in the env validation checks with the variable name or delete the constant if
you prefer to keep inline patterns.

In `@deploy/docker/tests/test-safe-env-loader.sh`:
- Around line 204-305: Add a new test in
deploy/docker/tests/test-safe-env-loader.sh that verifies sanitize_env_file
correctly escapes embedded single quotes inside dangerous command-substitution
values (e.g., APPSMITH_INSTANCE_NAME=$(cmd'with'quotes)Appsmith); in the test
call sanitize_env_file on a temp env file containing that value, then assert the
sanitized file passes validate_env_file and that safe_source_env exports the
variable with the single quotes preserved (use a new test name like
test_sanitize_handles_embedded_single_quotes and reference sanitize_env_file,
validate_env_file, and safe_source_env to locate the relevant logic).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 38bbfdd1-5401-4563-be59-67ee737ebdaf

📥 Commits

Reviewing files that changed from the base of the PR and between d44df5f and 37ccaf0.

📒 Files selected for processing (4)
  • deploy/docker/fs/opt/appsmith/entrypoint.sh
  • deploy/docker/fs/opt/appsmith/run-with-env.sh
  • deploy/docker/fs/opt/appsmith/safe-env-loader.sh
  • deploy/docker/tests/test-safe-env-loader.sh

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

Labels

Security Issues related to information security within the product

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant