Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions glassworm-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
name: "Glassworm Supply-Chain Check"
description: "Deterministic byte-level scanner for invisible Unicode obfuscation, malicious install hooks, and eval-based payload decoders associated with the Glassworm campaign."

# Required permissions: contents: read, pull-requests: write (for PR comments)

inputs:
extensions:
description: "Space-separated list of file extensions to scan (without dots)"
required: false
default: "js ts mjs cjs jsx tsx json yml yaml"
fail-on-warning:
description: "Whether to fail the check on warnings (not just critical findings)"
required: false
default: "false"

outputs:
found:
description: "Whether any findings were detected (true/false)"
value: ${{ steps.scan.outputs.found }}
critical:
description: "Whether critical findings were detected (true/false)"
value: ${{ steps.scan.outputs.critical }}
report:
description: "Path to the findings report markdown file"
value: ${{ steps.scan.outputs.report_file }}

runs:
using: "composite"
steps:
- name: Glassworm scan
id: scan
shell: bash
env:
SCAN_EXTENSIONS: ${{ inputs.extensions }}
FAIL_ON_WARNING: ${{ inputs.fail-on-warning }}
run: |
set -euo pipefail

FOUND_CRITICAL=0
FOUND_WARNING=0
REPORT=""

# Get changed files in this PR
BASE_REF="${GITHUB_BASE_REF:-main}"
Comment thread
ignaciosantise marked this conversation as resolved.
Outdated
FILES=$(git diff --name-only "origin/$BASE_REF"...HEAD 2>/dev/null || git diff --name-only HEAD~1...HEAD)

# Filter to matching extensions
SCAN_FILES=()
for f in $FILES; do
Comment thread
ignaciosantise marked this conversation as resolved.
Outdated
[ -f "$f" ] || continue
for ext in $SCAN_EXTENSIONS; do
if [[ "$f" == *".$ext" ]]; then
SCAN_FILES+=("$f")
break
fi
done
done

if [ ${#SCAN_FILES[@]} -eq 0 ]; then
echo "✅ No relevant files changed."
echo "found=false" >> "$GITHUB_OUTPUT"
echo "critical=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "Scanning ${#SCAN_FILES[@]} file(s) for Glassworm indicators..."

# ──────────────────────────────────────────────
# 1. Invisible PUA Unicode (Variation Selectors)
# U+FE00-FE0F → UTF-8: EF B8 80 – EF B8 8F
# U+E0100-E01EF → UTF-8: F3 A0 84 80 – F3 A0 87 AF
# ──────────────────────────────────────────────
for f in "${SCAN_FILES[@]}"; do
if xxd -p "$f" | tr -d '\n' | grep -qiE 'efb88[0-9a-f]|f3a084[89a-f][0-9a-f]|f3a08[5-7][0-9a-f][0-9a-f]'; then
REPORT+="🚨 **CRITICAL** — Invisible PUA Unicode characters in \`$f\`\n"
FOUND_CRITICAL=1
fi
done

# ──────────────────────────────────────────────
# 2. Zero-width characters in non-markdown files
# ──────────────────────────────────────────────
for f in "${SCAN_FILES[@]}"; do
[[ "$f" == *.md ]] && continue
if grep -Pq '[\x{200B}\x{200C}\x{200D}\x{2060}]' "$f" 2>/dev/null || true; then
Comment thread
ignaciosantise marked this conversation as resolved.
Outdated
if grep -Pc '[\x{200B}\x{200C}\x{200D}\x{2060}]' "$f" 2>/dev/null | grep -qv '^0$'; then
REPORT+="⚠️ **WARNING** — Zero-width Unicode characters in \`$f\`\n"
FOUND_WARNING=1
fi
fi
# Mid-file BOM
if [ "$(wc -c < "$f")" -gt 3 ]; then
if tail -c +4 "$f" | grep -Pq '\xef\xbb\xbf' 2>/dev/null; then
REPORT+="⚠️ **WARNING** — Mid-file BOM character in \`$f\`\n"
FOUND_WARNING=1
fi
fi
done

# ──────────────────────────────────────────────
# 3. Suspicious code patterns
# ──────────────────────────────────────────────
for f in "${SCAN_FILES[@]}"; do
if grep -Pq 'eval\s*\(.*Buffer\.from' "$f" 2>/dev/null; then
REPORT+="🚨 **CRITICAL** — \`eval(Buffer.from(...))\` pattern in \`$f\`\n"
FOUND_CRITICAL=1
fi
if grep -Pq 'codePointAt.*0x[Ff][Ee]0' "$f" 2>/dev/null; then
REPORT+="🚨 **CRITICAL** — Unicode decoder pattern (\`codePointAt\` + PUA range) in \`$f\`\n"
FOUND_CRITICAL=1
fi
if grep -Pq 'eval\s*\(.*\x60' "$f" 2>/dev/null; then
REPORT+="⚠️ **WARNING** — \`eval()\` with template literal in \`$f\`\n"
FOUND_WARNING=1
fi
done

# ──────────────────────────────────────────────
# 4. Install hooks added in package.json diffs
# ──────────────────────────────────────────────
for f in "${SCAN_FILES[@]}"; do
if [[ "$(basename "$f")" == "package.json" ]]; then
if git diff "origin/$BASE_REF"...HEAD -- "$f" 2>/dev/null | grep -Eq '^\+.*"(preinstall|postinstall|preuninstall)"'; then
REPORT+="⚠️ **WARNING** — Install hook added/modified in \`$f\` — verify this is intentional\n"
FOUND_WARNING=1
fi
fi
done

# ──────────────────────────────────────────────
# 5. Line-level byte anomaly detection
# Empty-looking lines with huge byte count
# ──────────────────────────────────────────────
for f in "${SCAN_FILES[@]}"; do
line_num=0
while IFS= read -r line || [ -n "$line" ]; do
line_num=$((line_num + 1))
bytes=$(printf '%s' "$line" | wc -c | tr -d ' ')
visible=$(printf '%s' "$line" | tr -cd '[:print:]' | wc -c | tr -d ' ')
if [ "$bytes" -gt 500 ] && [ "$visible" -lt 20 ]; then
REPORT+="🚨 **CRITICAL** — Obfuscated payload suspected in \`$f:$line_num\` — ${bytes} bytes but only ${visible} visible chars\n"
FOUND_CRITICAL=1
fi
done < "$f"
done

# ──────────────────────────────────────────────
# Output
# ──────────────────────────────────────────────
if [ "$FOUND_CRITICAL" -eq 1 ] || [ "$FOUND_WARNING" -eq 1 ]; then
REPORT_FILE="${RUNNER_TEMP:-/tmp}/glassworm-report-$$.md"

{
echo "## 🛡️ Glassworm Supply-Chain Security Alert"
echo ""
echo -e "$REPORT"
echo ""
echo "This PR contains patterns associated with the [Glassworm](https://www.aikido.dev/blog/glassworm-returns-unicode-attack-github-npm-vscode) supply-chain attack campaign."
Comment thread
ignaciosantise marked this conversation as resolved.
Outdated
if [ "$FOUND_CRITICAL" -eq 1 ]; then
echo ""
echo "**🚨 Critical findings detected — do not merge until investigated.**"
fi
} > "$REPORT_FILE"

# Job summary
cat "$REPORT_FILE" >> "$GITHUB_STEP_SUMMARY"

echo "found=true" >> "$GITHUB_OUTPUT"
echo "critical=$( [ "$FOUND_CRITICAL" -eq 1 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"
echo "report_file=$REPORT_FILE" >> "$GITHUB_OUTPUT"

# Determine exit code
if [ "$FOUND_CRITICAL" -eq 1 ]; then
exit 1
elif [ "$FAIL_ON_WARNING" = "true" ]; then
exit 1
fi
else
echo "✅ No Glassworm indicators found." >> "$GITHUB_STEP_SUMMARY"
echo "found=false" >> "$GITHUB_OUTPUT"
echo "critical=false" >> "$GITHUB_OUTPUT"
fi

- name: Comment on PR
Comment thread
ignaciosantise marked this conversation as resolved.
if: failure() && steps.scan.outputs.found == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
REPORT_FILE="${{ steps.scan.outputs.report_file }}"
if [ -f "$REPORT_FILE" ]; then
gh pr comment "${{ github.event.pull_request.number }}" \
--repo "${{ github.repository }}" \
--body-file "$REPORT_FILE"
fi
Loading