From 1e914fcc9ef647007433a899e8e0d00c6a1e31ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 12:17:43 +0000 Subject: [PATCH 1/2] Initial plan From cb437483c0426b777c6ad9edf6e7d72717e84a64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 12:23:52 +0000 Subject: [PATCH 2/2] Security hardening: fix shell injection, Nginx hardening, download integrity, Avalanchego host binding Co-authored-by: numbers-official <181934381+numbers-official@users.noreply.github.com> --- README.md | 16 +-- api/info.isBootstrapped.sh | 11 +- api/platform.getBlockchainStatus.sh | 11 +- api/platform.getCurrentValidators.sh | 11 +- api/platform.getValidatorsAt.sh | 12 +- api/platform.validatedBy.sh | 11 +- api/platform.validates.sh | 11 +- chains/install-subnet-cli.sh | 14 ++ chains/update-validator-mainnet.sh | 19 +++ chains/update-validator-testnet.sh | 19 +++ faucet/default | 123 +++-------------- rpc/testnet/etc/nginx/sites-available/default | 129 ++++-------------- subnet-cli/install-subnet-cli.sh | 14 ++ subnet-cli/subnet-cli-create-vmid.sh | 7 +- subnet-cli/subnet-cli-status-blockchain.sh | 7 +- 15 files changed, 149 insertions(+), 266 deletions(-) diff --git a/README.md b/README.md index c207e4b..166e2bd 100644 --- a/README.md +++ b/README.md @@ -286,15 +286,15 @@ waiting for validator 8CGJYaRLChC79CCRnvd7sh5eB9E9L9dVF to start validating GBEw Launch validator. When running `avalanchego`, add -* `-—http-host=0.0.0.0`: Make MetaMask can access the RPC URL -* `--http-allowed-hosts="*"`: Allow traffic from the RPC node (since v1.10.3) +* `--http-host=127.0.0.1`: Bind the HTTP server to localhost only. Expose RPC externally via a reverse proxy (e.g., Nginx). +* `--http-allowed-hosts="localhost,127.0.0.1,"`: Restrict allowed hosts (since v1.10.3) ```sh ./avalanchego \ --track-subnets=81vK49Udih5qmEzU7opx3Zg9AnB33F2oqUTQKuaoWgCvFUWQe\ --network-id=fuji \ - --http-host=0.0.0.0 \ - --http-allowed-hosts="*" \ + --http-host=127.0.0.1 \ + --http-allowed-hosts="localhost,127.0.0.1," \ --public-ip= ``` @@ -908,9 +908,9 @@ Make a Full Node instance to be an Archive Node instance: ./avalanchego \ --track-subnets=${SUBNET_MAINNET} \ - --http-host=0.0.0.0 \ + --http-host=127.0.0.1 \ --public-ip= \ - --http-allowed-hosts="*" + --http-allowed-hosts="localhost,127.0.0.1," ``` Run an archive node for testnet @@ -923,9 +923,9 @@ Make a Full Node instance to be an Archive Node instance: ./avalanchego \ --track-subnets=${SUBNET_MAINNET} \ - --http-host=0.0.0.0 \ + --http-host=127.0.0.1 \ --public-ip= \ - --http-allowed-hosts="*" + --http-allowed-hosts="localhost,127.0.0.1," ``` 1. (optional) Test an Archive Node diff --git a/api/info.isBootstrapped.sh b/api/info.isBootstrapped.sh index 2940dfd..b22f12c 100755 --- a/api/info.isBootstrapped.sh +++ b/api/info.isBootstrapped.sh @@ -6,11 +6,6 @@ URL="127.0.0.1:9650" CHAIN_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"info.isBootstrapped\", - \"params\":{ - \"chain\":\"${CHAIN_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' ${URL}/ext/info +curl -X POST --data "$(jq -n --arg chain "${CHAIN_ID}" \ + '{"jsonrpc":"2.0","method":"info.isBootstrapped","params":{"chain":$chain},"id":1}')" \ + -H 'content-type:application/json;' "${URL}/ext/info" diff --git a/api/platform.getBlockchainStatus.sh b/api/platform.getBlockchainStatus.sh index e6b1c25..9dfdc1a 100755 --- a/api/platform.getBlockchainStatus.sh +++ b/api/platform.getBlockchainStatus.sh @@ -10,11 +10,6 @@ URL="127.0.0.1:9650" BLOCKCHAIN_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"platform.getBlockchainStatus\", - \"params\":{ - \"blockchainID\":\"${BLOCKCHAIN_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' ${URL}/ext/P +curl -X POST --data "$(jq -n --arg id "${BLOCKCHAIN_ID}" \ + '{"jsonrpc":"2.0","method":"platform.getBlockchainStatus","params":{"blockchainID":$id},"id":1}')" \ + -H 'content-type:application/json;' "${URL}/ext/P" diff --git a/api/platform.getCurrentValidators.sh b/api/platform.getCurrentValidators.sh index 0e0f743..8b8e55c 100755 --- a/api/platform.getCurrentValidators.sh +++ b/api/platform.getCurrentValidators.sh @@ -5,11 +5,6 @@ URL="127.0.0.1:9650" SUBNET_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"platform.getCurrentValidators\", - \"params\": { - \"subnetID\": \"${SUBNET_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' ${URL}/ext/bc/P +curl -X POST --data "$(jq -n --arg id "${SUBNET_ID}" \ + '{"jsonrpc":"2.0","method":"platform.getCurrentValidators","params":{"subnetID":$id},"id":1}')" \ + -H 'content-type:application/json;' "${URL}/ext/bc/P" diff --git a/api/platform.getValidatorsAt.sh b/api/platform.getValidatorsAt.sh index 66ee968..a1a379d 100755 --- a/api/platform.getValidatorsAt.sh +++ b/api/platform.getValidatorsAt.sh @@ -2,12 +2,6 @@ SUBNET_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"platform.getValidatorsAt\", - \"params\": { - \"height\":1, - \"subnetID\": \"${SUBNET_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +curl -X POST --data "$(jq -n --arg id "${SUBNET_ID}" \ + '{"jsonrpc":"2.0","method":"platform.getValidatorsAt","params":{"height":1,"subnetID":$id},"id":1}')" \ + -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P diff --git a/api/platform.validatedBy.sh b/api/platform.validatedBy.sh index 236114c..296845c 100755 --- a/api/platform.validatedBy.sh +++ b/api/platform.validatedBy.sh @@ -2,11 +2,6 @@ BLOCKCHAIN_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"platform.validatedBy\", - \"params\": { - \"blockchainID\": \"${BLOCKCHAIN_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +curl -X POST --data "$(jq -n --arg id "${BLOCKCHAIN_ID}" \ + '{"jsonrpc":"2.0","method":"platform.validatedBy","params":{"blockchainID":$id},"id":1}')" \ + -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P diff --git a/api/platform.validates.sh b/api/platform.validates.sh index a41d4a7..4ed9221 100755 --- a/api/platform.validates.sh +++ b/api/platform.validates.sh @@ -2,12 +2,7 @@ SUBNET_ID="$1" -curl -X POST --data "{ - \"jsonrpc\": \"2.0\", - \"method\": \"platform.validates\", - \"params\": { - \"subnetID\":\"${SUBNET_ID}\" - }, - \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +curl -X POST --data "$(jq -n --arg id "${SUBNET_ID}" \ + '{"jsonrpc":"2.0","method":"platform.validates","params":{"subnetID":$id},"id":1}')" \ + -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P diff --git a/chains/install-subnet-cli.sh b/chains/install-subnet-cli.sh index 9b01c83..6018ed6 100755 --- a/chains/install-subnet-cli.sh +++ b/chains/install-subnet-cli.sh @@ -1,4 +1,7 @@ VERSION=0.0.2 # Populate latest here +# Update EXPECTED_SHA256 to match the SHA256 checksum for the downloaded version. +# Obtain the checksum from the official release page or the checksums file published with the release. +EXPECTED_SHA256="" # Populate expected SHA256 checksum here GOARCH=$(go env GOARCH) GOOS=$(go env GOOS) @@ -14,6 +17,17 @@ rm -f /tmp/subnet-cli echo "downloading subnet-cli ${VERSION} at ${DOWNLOAD_URL}" curl -L ${DOWNLOAD_URL} -o ${DOWNLOAD_PATH} +if [[ -n "${EXPECTED_SHA256}" ]]; then + echo "verifying checksum" + if ! echo "${EXPECTED_SHA256} ${DOWNLOAD_PATH}" | sha256sum -c -; then + echo "Error: checksum verification failed. Aborting." >&2 + rm -f ${DOWNLOAD_PATH} + exit 1 + fi +else + echo "Warning: EXPECTED_SHA256 is not set. Skipping checksum verification." >&2 +fi + echo "extracting downloaded subnet-cli" tar xzvf ${DOWNLOAD_PATH} -C /tmp diff --git a/chains/update-validator-mainnet.sh b/chains/update-validator-mainnet.sh index f740697..7d2007a 100755 --- a/chains/update-validator-mainnet.sh +++ b/chains/update-validator-mainnet.sh @@ -6,11 +6,29 @@ SUBNET_EVM_VERSION="0.5.6" # Numbers Mainnet VM_ID="qeX7kcVMMkVLB9ZJKTpvtSjpLbtYooNEdpFzFShwRTFu76qdx" SUBNET_ID="2gHgAgyDHQv7jzFg6MxU2yyKq5NZBpwFLFeP8xX2E3gyK1SzSQ" +# Update these checksums to match the expected SHA256 hashes for the downloaded versions. +# Obtain them from the official release pages on GitHub. +AVALANCHEGO_SHA256="" # Populate expected SHA256 for avalanchego tarball +SUBNET_EVM_SHA256="" # Populate expected SHA256 for subnet-evm tarball +verify_checksum() { + local expected="$1" + local file="$2" + if [[ -n "${expected}" ]]; then + echo "verifying checksum for ${file}" + if ! echo "${expected} ${file}" | sha256sum -c -; then + echo "Error: checksum verification failed for ${file}. Aborting." >&2 + exit 1 + fi + else + echo "Warning: expected checksum not set for ${file}. Skipping verification." >&2 + fi +} download_avalanchego() { echo "Step: download_avalanchego" wget https://github.com/ava-labs/avalanchego/releases/download/v${AVALANCHEGO_VERSION}/avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz + verify_checksum "${AVALANCHEGO_SHA256}" "avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz" tar xzf avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz cp avalanchego-v${AVALANCHEGO_PREVIOUS_VERSION}/run.sh avalanchego-v${AVALANCHEGO_VERSION}/ } @@ -19,6 +37,7 @@ download_sunbet_evm() { echo "Step: download_sunbet_evm" mkdir subnet-evm-${SUBNET_EVM_VERSION} wget https://github.com/ava-labs/subnet-evm/releases/download/v${SUBNET_EVM_VERSION}/subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz + verify_checksum "${SUBNET_EVM_SHA256}" "subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz" tar xzf subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz -C subnet-evm-${SUBNET_EVM_VERSION} } diff --git a/chains/update-validator-testnet.sh b/chains/update-validator-testnet.sh index 6f2c22d..9f2ddfc 100755 --- a/chains/update-validator-testnet.sh +++ b/chains/update-validator-testnet.sh @@ -6,11 +6,29 @@ SUBNET_EVM_VERSION="0.5.6" # Numbers Testnet VM_ID="kmYb53NrmqcW7gfV2FGHBHWXNA6YhhWf7R7LoQeGj9mdDYuaT" SUBNET_ID="81vK49Udih5qmEzU7opx3Zg9AnB33F2oqUTQKuaoWgCvFUWQe" +# Update these checksums to match the expected SHA256 hashes for the downloaded versions. +# Obtain them from the official release pages on GitHub. +AVALANCHEGO_SHA256="" # Populate expected SHA256 for avalanchego tarball +SUBNET_EVM_SHA256="" # Populate expected SHA256 for subnet-evm tarball +verify_checksum() { + local expected="$1" + local file="$2" + if [[ -n "${expected}" ]]; then + echo "verifying checksum for ${file}" + if ! echo "${expected} ${file}" | sha256sum -c -; then + echo "Error: checksum verification failed for ${file}. Aborting." >&2 + exit 1 + fi + else + echo "Warning: expected checksum not set for ${file}. Skipping verification." >&2 + fi +} download_avalanchego() { echo "Step: download_avalanchego" wget https://github.com/ava-labs/avalanchego/releases/download/v${AVALANCHEGO_VERSION}/avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz + verify_checksum "${AVALANCHEGO_SHA256}" "avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz" tar xzf avalanchego-linux-amd64-v${AVALANCHEGO_VERSION}.tar.gz cp avalanchego-v${AVALANCHEGO_PREVIOUS_VERSION}/run.sh avalanchego-v${AVALANCHEGO_VERSION}/ } @@ -19,6 +37,7 @@ download_sunbet_evm() { echo "Step: download_sunbet_evm" mkdir subnet-evm-${SUBNET_EVM_VERSION} wget https://github.com/ava-labs/subnet-evm/releases/download/v${SUBNET_EVM_VERSION}/subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz + verify_checksum "${SUBNET_EVM_SHA256}" "subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz" tar xzf subnet-evm_${SUBNET_EVM_VERSION}_linux_amd64.tar.gz -C subnet-evm-${SUBNET_EVM_VERSION} } diff --git a/faucet/default b/faucet/default index 512ca58..9213bf3 100644 --- a/faucet/default +++ b/faucet/default @@ -16,108 +16,38 @@ # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. ## +# Rate limiting: allow 5 requests/second per IP, burst up to 10 +limit_req_zone $binary_remote_addr zone=faucet_limit:10m rate=5r/s; + upstream faucet { server localhost:8000; } -# Default server configuration -# +# Default server configuration: redirect all HTTP to HTTPS server { listen 80 default_server; listen [::]:80 default_server; - - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - - root /var/www/html; - - # Add index.php to the list if you are using PHP - index index.html index.htm index.nginx-debian.html; - server_name _; - - location / { - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - } - - # pass PHP scripts to FastCGI server - # - #location ~ \.php$ { - # include snippets/fastcgi-php.conf; - # - # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/run/php/php7.4-fpm.sock; - # # With php-cgi (or other tcp sockets): - # fastcgi_pass 127.0.0.1:9000; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} + return 301 https://$host$request_uri; } - -# Virtual Host configuration for example.com -# -# You can move that to a different file under sites-available/ and symlink that -# to sites-enabled/ to enable it. -# -#server { -# listen 80; -# listen [::]:80; -# -# server_name example.com; -# -# root /var/www/example.com; -# index index.html; -# -# location / { -# try_files $uri $uri/ =404; -# } -#} - server { - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - root /var/www/html/faucet; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name faucet.num.network; # managed by Certbot + # Limit request body size to 1 MB + client_max_body_size 1m; + + # Security headers + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Content-Security-Policy "default-src 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. @@ -125,27 +55,16 @@ server { } location /api/ { + # Apply rate limiting + limit_req zone=faucet_limit burst=10 nodelay; + proxy_pass http://faucet; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; } - # pass PHP scripts to FastCGI server - # - #location ~ \.php$ { - # include snippets/fastcgi-php.conf; - # - # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/run/php/php7.4-fpm.sock; - # # With php-cgi (or other tcp sockets): - # fastcgi_pass 127.0.0.1:9000; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} - listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot diff --git a/rpc/testnet/etc/nginx/sites-available/default b/rpc/testnet/etc/nginx/sites-available/default index 5f7c54f..ad8015e 100644 --- a/rpc/testnet/etc/nginx/sites-available/default +++ b/rpc/testnet/etc/nginx/sites-available/default @@ -16,6 +16,9 @@ # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. ## +# Rate limiting: allow 10 requests/second per IP, burst up to 20 +limit_req_zone $binary_remote_addr zone=rpc_limit:10m rate=10r/s; + upstream validator { server :9650; server :9650; @@ -24,139 +27,55 @@ upstream validator { server :9650; } -# Default server configuration -# +# Default server configuration: redirect all HTTP to HTTPS server { listen 80 default_server; listen [::]:80 default_server; - - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - - root /var/www/html; - - # Add index.php to the list if you are using PHP - index index.html index.htm index.nginx-debian.html; - server_name _; - - location / { - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - } - - # pass PHP scripts to FastCGI server - # - #location ~ \.php$ { - # include snippets/fastcgi-php.conf; - # - # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/run/php/php7.4-fpm.sock; - # # With php-cgi (or other tcp sockets): - # fastcgi_pass 127.0.0.1:9000; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} + return 301 https://$host$request_uri; } - -# Virtual Host configuration for example.com -# -# You can move that to a different file under sites-available/ and symlink that -# to sites-enabled/ to enable it. -# -#server { -# listen 80; -# listen [::]:80; -# -# server_name example.com; -# -# root /var/www/example.com; -# index index.html; -# -# location / { -# try_files $uri $uri/ =404; -# } -#} - server { - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name testnetrpc.numbersprotocol.io; # managed by Certbot + # Limit request body size to 1 MB + client_max_body_size 1m; + + # Security headers + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Content-Security-Policy "default-src 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location / { - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - #try_files $uri $uri/ =404; + # Apply rate limiting + limit_req zone=rpc_limit burst=20 nodelay; proxy_pass http://validator/ext/bc/2oo5UvYgFQikM7KBsMXFQE3RQv3xAFFc8JY2GEBNBF1tp4JaeZ/rpc; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; } location /ws { + # Apply rate limiting + limit_req zone=rpc_limit burst=20 nodelay; + proxy_pass http://validator/ext/bc/2oo5UvYgFQikM7KBsMXFQE3RQv3xAFFc8JY2GEBNBF1tp4JaeZ/ws; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } - # pass PHP scripts to FastCGI server - # - #location ~ \.php$ { - # include snippets/fastcgi-php.conf; - # - # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/run/php/php7.4-fpm.sock; - # # With php-cgi (or other tcp sockets): - # fastcgi_pass 127.0.0.1:9000; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} - listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot diff --git a/subnet-cli/install-subnet-cli.sh b/subnet-cli/install-subnet-cli.sh index 9b01c83..6018ed6 100755 --- a/subnet-cli/install-subnet-cli.sh +++ b/subnet-cli/install-subnet-cli.sh @@ -1,4 +1,7 @@ VERSION=0.0.2 # Populate latest here +# Update EXPECTED_SHA256 to match the SHA256 checksum for the downloaded version. +# Obtain the checksum from the official release page or the checksums file published with the release. +EXPECTED_SHA256="" # Populate expected SHA256 checksum here GOARCH=$(go env GOARCH) GOOS=$(go env GOOS) @@ -14,6 +17,17 @@ rm -f /tmp/subnet-cli echo "downloading subnet-cli ${VERSION} at ${DOWNLOAD_URL}" curl -L ${DOWNLOAD_URL} -o ${DOWNLOAD_PATH} +if [[ -n "${EXPECTED_SHA256}" ]]; then + echo "verifying checksum" + if ! echo "${EXPECTED_SHA256} ${DOWNLOAD_PATH}" | sha256sum -c -; then + echo "Error: checksum verification failed. Aborting." >&2 + rm -f ${DOWNLOAD_PATH} + exit 1 + fi +else + echo "Warning: EXPECTED_SHA256 is not set. Skipping checksum verification." >&2 +fi + echo "extracting downloaded subnet-cli" tar xzvf ${DOWNLOAD_PATH} -C /tmp diff --git a/subnet-cli/subnet-cli-create-vmid.sh b/subnet-cli/subnet-cli-create-vmid.sh index 3a7fca3..a1a30cf 100755 --- a/subnet-cli/subnet-cli-create-vmid.sh +++ b/subnet-cli/subnet-cli-create-vmid.sh @@ -5,5 +5,10 @@ # Example: numbersevm SUBNET_EVM_NAME="$1" -subnet-cli create VMID $SUBNET_EVM_NAME +if [[ ! "${SUBNET_EVM_NAME}" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo "Error: invalid VM name. Only alphanumeric characters, hyphens, and underscores are allowed." >&2 + exit 1 +fi + +subnet-cli create VMID "${SUBNET_EVM_NAME}" diff --git a/subnet-cli/subnet-cli-status-blockchain.sh b/subnet-cli/subnet-cli-status-blockchain.sh index 9a87251..25205bf 100755 --- a/subnet-cli/subnet-cli-status-blockchain.sh +++ b/subnet-cli/subnet-cli-status-blockchain.sh @@ -3,7 +3,12 @@ # Numbers devnet BLOCKCHAIN_ID="$1" +if [[ ! "${BLOCKCHAIN_ID}" =~ ^[a-km-zA-HJ-NP-Z1-9]+$ ]]; then + echo "Error: invalid blockchain ID. Only base58 characters are allowed." >&2 + exit 1 +fi + subnet-cli status blockchain \ --private-uri="http://127.0.0.1:9650" \ - --blockchain-id=${BLOCKCHAIN_ID} \ + --blockchain-id="${BLOCKCHAIN_ID}" \ --check-bootstrapped