Compare commits
8 Commits
d2a0a0f4cc
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f362bd3721 | ||
|
|
7585a12b6d | ||
|
|
50aa38712e | ||
|
|
c5037c0ac0 | ||
|
|
f257fcfcb9 | ||
|
|
d9b4592c50 | ||
|
|
72a8f37290 | ||
|
|
4eee88a004 |
@@ -5,7 +5,7 @@ Quick scanner for CVE-2025-66478 / CVE-2025-55182 (CVSS 10.0)
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -o check-nextjs-rce.sh http://100.120.125.113:3000/pdm/security-tools/raw/branch/main/check-nextjs-rce.sh
|
curl -o check-nextjs-rce.sh http://100.120.125.113:3000/pdm/security-tools/raw/branch/master/check-nextjs-rce.sh
|
||||||
chmod +x check-nextjs-rce.sh
|
chmod +x check-nextjs-rce.sh
|
||||||
sudo ./check-nextjs-rce.sh
|
sudo ./check-nextjs-rce.sh
|
||||||
```
|
```
|
||||||
|
|||||||
65
README.md
65
README.md
@@ -2,6 +2,71 @@
|
|||||||
|
|
||||||
A collection of security scripts versioned in this repository.
|
A collection of security scripts versioned in this repository.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
### check-npm-sudo-config.sh
|
||||||
|
|
||||||
|
Audits npm configuration on a Linux VM to detect cases where npm is — or has
|
||||||
|
been — configured to install packages into system-owned directories, which
|
||||||
|
requires `sudo` and creates security risks.
|
||||||
|
|
||||||
|
Running `sudo npm install -g` can deposit files owned by root inside your npm
|
||||||
|
prefix or cache directory. This causes permission errors for non-root users,
|
||||||
|
encourages further `sudo npm` use to work around them, and means malicious
|
||||||
|
packages run with root privileges during installation.
|
||||||
|
|
||||||
|
**This script is audit-only — it makes no changes.** It reports issues and
|
||||||
|
prints recommended commands, but you must run those commands yourself.
|
||||||
|
|
||||||
|
The script checks:
|
||||||
|
|
||||||
|
1. **npm prefix** — flags if it points to `/usr` or `/usr/local` (system-wide, requires sudo)
|
||||||
|
2. **~/.npmrc** — checks whether the prefix is explicitly pinned to a user directory
|
||||||
|
3. **PATH** — confirms the npm prefix bin directory is in PATH
|
||||||
|
4. **Root-owned files in the prefix** — evidence of past `sudo npm` usage
|
||||||
|
5. **Shell history** — scans `.bash_history` / `.zsh_history` for `sudo npm` commands
|
||||||
|
6. **npm cache ownership** — root-owned cache files cause EACCES errors
|
||||||
|
7. **Node version manager** — detects nvm, fnm, or n; flags if n is present without N_PREFIX set
|
||||||
|
|
||||||
|
If issues are found, it sends a Telegram alert and logs results to `logs/`.
|
||||||
|
|
||||||
|
The correct fix is to configure npm to install global packages into a
|
||||||
|
user-owned directory (e.g. `~/.npm-global`) so that `sudo` is never needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm config set prefix ~/.npm-global
|
||||||
|
export PATH="$HOME/.npm-global/bin:$PATH"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standalone Scripts
|
||||||
|
|
||||||
|
These scripts live in `standalone/` and are **not run by `setup.sh`**. They are
|
||||||
|
single-use tools intended to be copied to a target machine and run manually.
|
||||||
|
|
||||||
|
### standalone/bind-ssh-tailscale.sh
|
||||||
|
|
||||||
|
Binds SSH to the Tailscale interface only and disables password authentication.
|
||||||
|
|
||||||
|
- Requires root (`sudo bash bind-ssh-tailscale.sh`)
|
||||||
|
- Tailscale must be installed and connected before running
|
||||||
|
- Uses a drop-in config at `/etc/ssh/sshd_config.d/99-tailscale-only.conf` if
|
||||||
|
that directory exists; otherwise edits `/etc/ssh/sshd_config` directly with
|
||||||
|
an automatic backup
|
||||||
|
- Validates the config with `sshd -t` before restarting the SSH service
|
||||||
|
- Prints revert instructions on completion
|
||||||
|
|
||||||
|
**To use on a target machine:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -O https://gitea.pdmarf.co.uk/pdm/security-tools/raw/branch/master/standalone/bind-ssh-tailscale.sh
|
||||||
|
# or via Tailscale:
|
||||||
|
curl -O http://100.120.125.113:3000/pdm/security-tools/raw/branch/master/standalone/bind-ssh-tailscale.sh
|
||||||
|
|
||||||
|
sudo bash bind-ssh-tailscale.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Claude Code Context
|
## Claude Code Context
|
||||||
|
|
||||||
This project is maintained with Claude Code. The working directory on macOS is:
|
This project is maintained with Claude Code. The working directory on macOS is:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# check-npm-sudo-config.sh
|
# check-npm-sudo-config.sh v1.0
|
||||||
# Audits npm configuration on this VM for sudo-related issues and recommends fixes.
|
# Audits npm configuration on this VM for sudo-related issues and recommends fixes.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -17,6 +17,8 @@ send_telegram() {
|
|||||||
|
|
||||||
HOSTNAME=$(hostname)
|
HOSTNAME=$(hostname)
|
||||||
DATE=$(date)
|
DATE=$(date)
|
||||||
|
LOGFILE="$SCRIPT_DIR/logs/npm-sudo-config-$(date +%Y%m%d).log"
|
||||||
|
mkdir -p "$SCRIPT_DIR/logs"
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -27,12 +29,12 @@ RESET='\033[0m'
|
|||||||
ISSUES=0
|
ISSUES=0
|
||||||
WARNINGS=0
|
WARNINGS=0
|
||||||
|
|
||||||
log() { echo "$*"; }
|
log() { echo "$*" | tee -a "$LOGFILE"; }
|
||||||
ok() { printf "${GREEN}✓${RESET} %s\n" "$*"; }
|
ok() { log "$(printf "${GREEN}✓${RESET} %s" "$*")"; }
|
||||||
warn() { printf "${YELLOW}⚠${RESET} %s\n" "$*"; (( WARNINGS++ )) || true; }
|
warn() { log "$(printf "${YELLOW}⚠${RESET} %s" "$*")"; (( WARNINGS++ )) || true; }
|
||||||
fail() { printf "${RED}✗${RESET} %s\n" "$*"; (( ISSUES++ )) || true; }
|
fail() { log "$(printf "${RED}✗${RESET} %s" "$*")"; (( ISSUES++ )) || true; }
|
||||||
rec() { printf " ${YELLOW}→${RESET} %s\n" "$*"; }
|
rec() { log "$(printf " ${YELLOW}→${RESET} %s" "$*")"; }
|
||||||
header() { echo ""; echo "=========================================="; echo "$*"; echo "=========================================="; }
|
header() { log ""; log "=========================================="; log "$*"; log "=========================================="; }
|
||||||
|
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log " npm sudo config audit"
|
log " npm sudo config audit"
|
||||||
@@ -179,6 +181,7 @@ fi
|
|||||||
# ── Summary ───────────────────────────────────────────────────────────────────
|
# ── Summary ───────────────────────────────────────────────────────────────────
|
||||||
header "SUMMARY"
|
header "SUMMARY"
|
||||||
log "Scan completed at: $(date)"
|
log "Scan completed at: $(date)"
|
||||||
|
log "Log saved to : $LOGFILE"
|
||||||
log ""
|
log ""
|
||||||
|
|
||||||
if [[ $ISSUES -gt 0 ]]; then
|
if [[ $ISSUES -gt 0 ]]; then
|
||||||
|
|||||||
10
setup.sh
10
setup.sh
@@ -9,6 +9,10 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
echo "=== Security Tools Setup ==="
|
echo "=== Security Tools Setup ==="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# ── Git config ────────────────────────────────────────────────────────────────
|
||||||
|
git -C "$SCRIPT_DIR" config pull.rebase false
|
||||||
|
echo "Git pull strategy set to merge."
|
||||||
|
|
||||||
# ── Telegram credentials ───────────────────────────────────────────────────────
|
# ── Telegram credentials ───────────────────────────────────────────────────────
|
||||||
if [[ -f "$SCRIPT_DIR/config.sh" ]]; then
|
if [[ -f "$SCRIPT_DIR/config.sh" ]]; then
|
||||||
echo "config.sh already exists — skipping credential setup."
|
echo "config.sh already exists — skipping credential setup."
|
||||||
@@ -99,6 +103,10 @@ echo ""
|
|||||||
echo "Running initial security scan..."
|
echo "Running initial security scan..."
|
||||||
bash "$SCRIPT_DIR/npm-security-check.sh" >> "$SCRIPT_DIR/logs/npm-security-check-$(date +%Y%m%d).log" 2>&1 && echo "npm-security-check: done." || echo "npm-security-check: issues found — check Telegram."
|
bash "$SCRIPT_DIR/npm-security-check.sh" >> "$SCRIPT_DIR/logs/npm-security-check-$(date +%Y%m%d).log" 2>&1 && echo "npm-security-check: done." || echo "npm-security-check: issues found — check Telegram."
|
||||||
bash "$SCRIPT_DIR/check-nextjs-rce.sh" >> "$SCRIPT_DIR/logs/check-nextjs-rce-$(date +%Y%m%d).log" 2>&1 && echo "check-nextjs-rce: done." || echo "check-nextjs-rce: issues found — check Telegram."
|
bash "$SCRIPT_DIR/check-nextjs-rce.sh" >> "$SCRIPT_DIR/logs/check-nextjs-rce-$(date +%Y%m%d).log" 2>&1 && echo "check-nextjs-rce: done." || echo "check-nextjs-rce: issues found — check Telegram."
|
||||||
bash "$SCRIPT_DIR/check-npm-sudo-config.sh" >> "$SCRIPT_DIR/logs/check-npm-sudo-config-$(date +%Y%m%d).log" 2>&1 && echo "check-npm-sudo-config: done." || echo "check-npm-sudo-config: issues found — check Telegram."
|
NPM_SUDO_LOG="$SCRIPT_DIR/logs/check-npm-sudo-config-$(date +%Y%m%d).log"
|
||||||
|
echo ""
|
||||||
|
echo "--- npm sudo config audit results ---"
|
||||||
|
bash "$SCRIPT_DIR/check-npm-sudo-config.sh" 2>&1 | tee -a "$NPM_SUDO_LOG"
|
||||||
|
echo "-------------------------------------"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Initial scan complete. Check Telegram for any alerts."
|
echo "Initial scan complete. Check Telegram for any alerts."
|
||||||
|
|||||||
75
standalone/bind-ssh-tailscale.sh
Executable file
75
standalone/bind-ssh-tailscale.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"; }
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
log "ERROR: Please run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Tailscale is installed and connected
|
||||||
|
if ! command -v tailscale &>/dev/null; then
|
||||||
|
log "ERROR: Tailscale is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAILSCALE_IP=$(tailscale ip -4 2>/dev/null)
|
||||||
|
if [ -z "$TAILSCALE_IP" ]; then
|
||||||
|
log "ERROR: Could not get Tailscale IP — is Tailscale connected?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "Tailscale IP: ${TAILSCALE_IP}"
|
||||||
|
|
||||||
|
# Detect SSH service name
|
||||||
|
if systemctl is-active --quiet ssh 2>/dev/null; then
|
||||||
|
SSH_SERVICE="ssh"
|
||||||
|
elif systemctl is-active --quiet sshd 2>/dev/null; then
|
||||||
|
SSH_SERVICE="sshd"
|
||||||
|
else
|
||||||
|
log "ERROR: No running SSH service found (tried ssh, sshd)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use a drop-in file if sshd_config.d exists, otherwise edit sshd_config directly
|
||||||
|
if [ -d /etc/ssh/sshd_config.d ]; then
|
||||||
|
DROPIN="/etc/ssh/sshd_config.d/99-tailscale-only.conf"
|
||||||
|
[ -f "$DROPIN" ] && log "WARNING: ${DROPIN} already exists — overwriting"
|
||||||
|
cat > "$DROPIN" << EOF
|
||||||
|
# Bind SSH to Tailscale interface only
|
||||||
|
# To revert: rm ${DROPIN} && systemctl restart ${SSH_SERVICE}
|
||||||
|
ListenAddress ${TAILSCALE_IP}
|
||||||
|
PasswordAuthentication no
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
EOF
|
||||||
|
log "Written: ${DROPIN}"
|
||||||
|
else
|
||||||
|
BACKUP="/etc/ssh/sshd_config.bak.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
cp /etc/ssh/sshd_config "$BACKUP"
|
||||||
|
log "Backed up sshd_config to ${BACKUP}"
|
||||||
|
|
||||||
|
# Remove any existing ListenAddress lines and add ours
|
||||||
|
sed -i '/^[#]*ListenAddress/d' /etc/ssh/sshd_config
|
||||||
|
echo "ListenAddress ${TAILSCALE_IP}" >> /etc/ssh/sshd_config
|
||||||
|
log "Updated /etc/ssh/sshd_config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate config before restarting
|
||||||
|
if ! sshd -t; then
|
||||||
|
log "ERROR: SSH config validation failed — aborting without restart"
|
||||||
|
[ -n "${DROPIN:-}" ] && rm -f "$DROPIN"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "SSH config validated OK"
|
||||||
|
|
||||||
|
systemctl restart "$SSH_SERVICE"
|
||||||
|
log "SSH service restarted"
|
||||||
|
|
||||||
|
log ""
|
||||||
|
log "Done. SSH is now bound to Tailscale only (${TAILSCALE_IP})"
|
||||||
|
log "Connect with: ssh root@${TAILSCALE_IP}"
|
||||||
|
if [ -d /etc/ssh/sshd_config.d ]; then
|
||||||
|
log "To revert: rm ${DROPIN} && systemctl restart ${SSH_SERVICE}"
|
||||||
|
else
|
||||||
|
log "To revert: cp ${BACKUP} /etc/ssh/sshd_config && systemctl restart ${SSH_SERVICE}"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user