From 3a8b51c46c9b04cc83adef44435b772239b05ed5 Mon Sep 17 00:00:00 2001 From: Mathew Dodgson Date: Mon, 25 May 2026 11:14:39 +1000 Subject: [PATCH] [Fix] auth header: Add all valid base64 chars to sanitize function --- nvm.sh | 9 ++++- test/fast/Unit tests/nvm_sanitize_auth_header | 38 +++++++++++++++++++ test/fast/Unit tests/security_wget_injection | 4 +- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100755 test/fast/Unit tests/nvm_sanitize_auth_header mode change 100644 => 100755 test/fast/Unit tests/security_wget_injection diff --git a/nvm.sh b/nvm.sh index fd504785..6e33c55b 100755 --- a/nvm.sh +++ b/nvm.sh @@ -186,8 +186,13 @@ nvm_download() { } nvm_sanitize_auth_header() { - # Remove potentially dangerous characters - nvm_echo "$1" | command sed 's/[^a-zA-Z0-9:;_. -]//g' + # Remove potentially dangerous characters; allow the full base64 (A-Za-z0-9+/=) + # and base64url (A-Za-z0-9-_=) charsets, plus the space, colon, dot, and + # underscore the previous allowlist already permitted, so that values like + # `Basic ` and `Bearer ` survive intact. + # token68's '~' is still stripped. + # Note: '-' must be at the end of the bracket expression to be treated as a literal. + nvm_echo "$1" | command sed 's/[^a-zA-Z0-9 :_.+/=-]//g' } nvm_has_system_node() { diff --git a/test/fast/Unit tests/nvm_sanitize_auth_header b/test/fast/Unit tests/nvm_sanitize_auth_header new file mode 100755 index 00000000..e10f1b6e --- /dev/null +++ b/test/fast/Unit tests/nvm_sanitize_auth_header @@ -0,0 +1,38 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +\. ../../../nvm.sh + +set -ex + +# Test 1: all standard base64 characters (RFC 4648) are preserved +STANDARD_B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" +RESULT=$(nvm_sanitize_auth_header "${STANDARD_B64}") +[ "${RESULT}" = "${STANDARD_B64}" ] || die "FAIL: standard base64 chars were stripped. Got: '${RESULT}'" + +# Test 2: all base64url characters (RFC 4648 ยง5) are preserved +B64URL="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=" +RESULT=$(nvm_sanitize_auth_header "${B64URL}") +[ "${RESULT}" = "${B64URL}" ] || die "FAIL: base64url chars were stripped. Got: '${RESULT}'" + +# Test 3: a real JWT Bearer token (base64url-encoded header.payload.signature) is preserved +JWT_TOKEN="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" +RESULT=$(nvm_sanitize_auth_header "${JWT_TOKEN}") +[ "${RESULT}" = "${JWT_TOKEN}" ] || die "FAIL: JWT Bearer token chars were stripped. Got: '${RESULT}'" + +# Test 4: Basic auth (base64-encoded user:pass) is preserved +BASIC_TOKEN="Basic dXNlcm5hbWU6cGFzc3dvcmQ=" +RESULT=$(nvm_sanitize_auth_header "${BASIC_TOKEN}") +[ "${RESULT}" = "${BASIC_TOKEN}" ] || die "FAIL: Basic auth base64 token chars were stripped. Got: '${RESULT}'" + +# Test 5: dangerous shell metacharacters are removed +DANGEROUS="Bearer token;\`evil\`-cmd \$(inject)" +RESULT=$(nvm_sanitize_auth_header "${DANGEROUS}") +case "${RESULT}" in + *";"*|*"\`"*|*'$'*|*"("*|*")"*) + die "FAIL: dangerous shell metacharacters survived sanitization. Got: '${RESULT}'" + ;; +esac + +echo "All nvm_sanitize_auth_header tests passed" diff --git a/test/fast/Unit tests/security_wget_injection b/test/fast/Unit tests/security_wget_injection old mode 100644 new mode 100755 index 0d51fd87..ea0c2a97 --- a/test/fast/Unit tests/security_wget_injection +++ b/test/fast/Unit tests/security_wget_injection @@ -32,9 +32,9 @@ fi # Test 2: Verify that sanitized header still works for legitimate requests # The sanitized header should only contain safe characters SANITIZED=$(nvm_sanitize_auth_header "${MALICIOUS_HEADER}") -# Verify that dangerous characters were removed +# Verify that dangerous shell metacharacters were removed case "${SANITIZED}" in - *";"*|*"touch"*|*"/tmp"*) + *";"*|*'$'*|*"\`"*) die "SECURITY FAILURE: Sanitization did not remove dangerous characters properly" ;; esac