coder / coder/registry

Audit and harden all module shell scripts against command injection (follow-up from dotfiles fix)

Open
#712 1 comment 0 reactions 0 assignees View on GitHub
security
Dominant language
HCL
Stars
79
Forks
161
Avg merge
1d 10h
Merged PRs (30d)
38

Description

## Context

The `dotfiles` module recently received a fix to address insecure shell expansion and missing input validation in its `run.sh` script. The fix added:
- Strict character whitelist validation on URI inputs
- URL scheme validation (only `https?://`, `ssh://`, `git@`, `git://`)
- Proper double-quoting of all shell variables

This same class of vulnerability — **unvalidated and/or unquoted user-controllable inputs interpolated into shell scripts** — exists across many other modules in the registry. These need the same treatment.

## Affected Modules

### High Priority (user-provided URLs/paths used without validation)

**`git-clone/run.sh`**
- `REPO_URL` is passed directly to `git clone` with **no input validation** (no character whitelist, no URL format check)
- `CLONE_PATH` and `BRANCH_NAME` are also unvalidated
- `POST_CLONE_SCRIPT` is base64-decoded and executed (by design, but worth noting)

**`personalize/run.sh`**
- `$SCRIPT` (from `PERSONALIZE_PATH`) is used **unquoted** in multiple places: `[ ! -f $SCRIPT ]`, `[ ! -x $SCRIPT ]`, and direct execution `$SCRIPT`
- Word splitting and globbing possible via crafted paths

**`filebrowser/run.sh`**
- `$ROOT_DIR`, `${DB_PATH}`, `${LOG_PATH}`, `${SERVER_BASE_PATH}`, `${PORT}` are used **unquoted** in commands
- e.g. `filebrowser config set --baseURL=${SERVER_BASE_PATH} --port=${PORT} ... --root=$ROOT_DIR`
- `tee -a ${LOG_PATH}` is also unquoted

**`code-server/run.sh`**
- `${ADDITIONAL_ARGS}` is expanded **unquoted** in the `run_code_server` function
- Extension names passed to `--install-extension` without validation

### Medium Priority (internal/credential values, but still unquoted)

**`jfrog-oauth/run.sh`** and **`jfrog-token/run.sh`**
- `${JFROG_URL}`, `${JFROG_SERVER_ID}`, `${ARTIFACTORY_USERNAME}` used without quoting
- `${REGISTER_DOCKER}` is expanded and executed as a bare command

**`vault-github/run.sh`**
- `${AUTH_PATH}`, `${GITHUB_EXTERNAL_AUTH_ID}` used in commands without strict validation

**`vault-jwt/run.sh`**
- `${VAULT_JWT_AUTH_PATH}`, `${VAULT_JWT_ROLE}` used in `vault write` command without validation

**`vault-token/run.sh`**
- `${VAULT_NAMESPACE}` used without validation

**`github-upload-public-key/run.sh`**
- `$CODER_EXTERNAL_AUTH_ID` used unquoted in commands
- `$GITHUB_API_URL` used unquoted in `curl` calls

## Recommended Fix Pattern

Follow the pattern established in the `dotfiles` module fix:

1. **Input validation** — For URL inputs, add a strict character whitelist regex (e.g. `[^a-zA-Z0-9._/:@-]`) and validate the URL scheme. For path inputs, validate against shell metacharacters.
2. **Quote all variables** — Every `$VAR` and `${VAR}` used in shell commands must be wrapped in double quotes to prevent word splitting and globbing.
3. **`set -euo pipefail`** — Ensure all scripts start with this for fail-fast behavior (some already do, some don't).
4. **Test coverage** — Verify that valid inputs still work and that payloads containing `;`, `&`, `|`, `$`, backticks, `(`, `)` etc. are rejected.

## Example: `git-clone/run.sh`

Before:
```bash
REPO_URL="${REPO_URL}"
# ... no validation ...
git clone "$REPO_URL" "$CLONE_PATH"
```

After (following dotfiles pattern):
```bash
REPO_URL="${REPO_URL}"
if [ -n "$REPO_URL" ]; then
if [[ "$REPO_URL" =~ [^a-zA-Z0-9._/:@-] ]]; then
echo "ERROR: REPO_URL contains invalid characters" >&2
exit 1
fi
if ! [[ "$REPO_URL" =~ ^(https?://|ssh://|git@|git://) ]]; then
echo "ERROR: REPO_URL must be a valid repository URL" >&2
exit 1
fi
fi
```

Created on behalf of @DevelopmentCats

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.