Last active
November 26, 2025 19:21
-
-
Save ruivieira/f80c35e83eebe09e61011cc14ba53710 to your computer and use it in GitHub Desktop.
Script to check Shai-Hulud packages (LIST NOT COMPREHENSIVE)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| CYAN='\033[0;36m' | |
| NC='\033[0m' | |
| DUNE_SEARCH_MESSAGES=( | |
| "He who controls the lockfiles controls the universe…" | |
| "Walking without rhythm so we don’t attract Shai-Hulud… yet." | |
| "Muad'Dib audits the dependencies. You should, too." | |
| "Casting the gom jabbar of grep onto your lockfiles." | |
| "Searching the desert of packages for signs of corruption." | |
| "The spice extends life. These dependencies? Unclear." | |
| ) | |
| DUNE_HIT_MESSAGES=( | |
| "Shai-Hulud has surfaced — a worm of dependency has been found." | |
| "You tried to walk without rhythm, but the worm still came." | |
| "The spice must flow, but these packages should probably go." | |
| "The Fremen would not tolerate such weak packages." | |
| "I must not fear. I will audit. I will remove." | |
| ) | |
| rand_msg() { | |
| local -n arr=$1 | |
| local size=${#arr[@]} | |
| if [ "$size" -eq 0 ]; then | |
| return | |
| fi | |
| local idx=$(( RANDOM % size )) | |
| echo "${arr[$idx]}" | |
| } | |
| ROOT_DIR="${1:-.}" | |
| AFFECTED_PACKAGES=( | |
| "@actbase/css-to-react-native-transform" | |
| "@actbase/node-server" | |
| "@actbase/react-absolute" | |
| "@actbase/react-daum-postcode" | |
| "@actbase/react-kakaosdk" | |
| "@actbase/react-native-actionsheet" | |
| "@actbase/react-native-devtools" | |
| "@actbase/react-native-fast-image" | |
| "@actbase/react-native-kakao-channel" | |
| "@actbase/react-native-kakao-navi" | |
| "@actbase/react-native-less-transformer" | |
| "@actbase/react-native-naver-login" | |
| "@actbase/react-native-simple-video" | |
| "@actbase/react-native-tiktok" | |
| "@alaan/s2s-auth" | |
| "@aryanhussain/my-angular-lib" | |
| "@asyncapi/avro-schema-parser" | |
| "@asyncapi/bundler" | |
| "@asyncapi/cli" | |
| "@asyncapi/converter" | |
| "@asyncapi/diff" | |
| "@asyncapi/dotnet-rabbitmq-template" | |
| "@asyncapi/edavisualiser" | |
| "@asyncapi/generator" | |
| "@asyncapi/generator-components" | |
| "@asyncapi/generator-helpers" | |
| "@asyncapi/generator-react-sdk" | |
| "@asyncapi/go-watermill-template" | |
| "@asyncapi/html-template" | |
| "@asyncapi/java-spring-cloud-stream-template" | |
| "@asyncapi/java-spring-template" | |
| "@asyncapi/java-template" | |
| "@asyncapi/keeper" | |
| "@asyncapi/markdown-template" | |
| "@asyncapi/modelina" | |
| "@asyncapi/modelina-cli" | |
| "@asyncapi/multi-parser" | |
| "@asyncapi/nodejs-template" | |
| "@asyncapi/nodejs-ws-template" | |
| "@asyncapi/nunjucks-filters" | |
| "@asyncapi/openapi-schema-parser" | |
| "@asyncapi/optimizer" | |
| "@asyncapi/parser" | |
| "@asyncapi/php-template" | |
| "@asyncapi/problem" | |
| "@asyncapi/protobuf-schema-parser" | |
| "@asyncapi/python-paho-template" | |
| "@asyncapi/react-component" | |
| "@asyncapi/server-api" | |
| "@asyncapi/specs" | |
| "@asyncapi/web-component" | |
| "@caretive/caret-cli" | |
| "@ensdomains/address-encoder" | |
| "@ensdomains/blacklist" | |
| "@ensdomains/buffer" | |
| "@ensdomains/ccip-read-dns-gateway" | |
| "@ensdomains/ccip-read-router" | |
| "@ensdomains/ccip-read-worker-viem" | |
| "@ensdomains/content-hash" | |
| "@ensdomains/curvearithmetics" | |
| "@ensdomains/cypress-metamask" | |
| "@ensdomains/dnsprovejs" | |
| "@ensdomains/dnssec-oracle-anchors" | |
| "@ensdomains/dnssecoraclejs" | |
| "@ensdomains/durin-middleware" | |
| "@ensdomains/ens-archived-contracts" | |
| "@ensdomains/ens-avatar" | |
| "@ensdomains/ens-validation" | |
| "@ensdomains/eth-ens-namehash" | |
| "@ensdomains/hackathon-registrar" | |
| "@ensdomains/hardhat-chai-matchers-viem" | |
| "@ensdomains/hardhat-toolbox-viem-extended" | |
| "@ensdomains/mock" | |
| "@ensdomains/name-wrapper" | |
| "@ensdomains/offchain-resolver-contracts" | |
| "@ensdomains/react-ens-address" | |
| "@ensdomains/renewal" | |
| "@ensdomains/renewal-widget" | |
| "@ensdomains/reverse-records" | |
| "@ensdomains/server-analytics" | |
| "@ensdomains/solsha1" | |
| "@ensdomains/subdomain-registrar" | |
| "@ensdomains/test-utils" | |
| "@ensdomains/thorin" | |
| "@ensdomains/ui" | |
| "@ensdomains/unicode-confusables" | |
| "@ensdomains/unruggable-gateways" | |
| "@ensdomains/vite-plugin-i18next-loader" | |
| "@ensdomains/web3modal" | |
| "@kvytech/cli" | |
| "@kvytech/components" | |
| "@kvytech/medusa-plugin-announcement" | |
| "@kvytech/medusa-plugin-management" | |
| "@kvytech/medusa-plugin-newsletter" | |
| "@kvytech/medusa-plugin-product-reviews" | |
| "@kvytech/web" | |
| "@louisle2/cortex-js" | |
| "@markvivanco/app-version-checker" | |
| "@mcp-use/cli" | |
| "@mcp-use/inspector" | |
| "@mcp-use/mcp-use" | |
| "@mparpaillon/connector-parse" | |
| "@mparpaillon/imagesloaded" | |
| "@mparpaillon/page" | |
| "@orbitgtbelgium/mapbox-gl-draw-scale-rotate-mode" | |
| "@orbitgtbelgium/orbit-components" | |
| "@orbitgtbelgium/time-slider" | |
| "@posthog/agent" | |
| "@posthog/ai" | |
| "@posthog/automatic-cohorts-plugin" | |
| "@posthog/cli" | |
| "@posthog/core" | |
| "@posthog/currency-normalization-plugin" | |
| "@posthog/customerio-plugin" | |
| "@posthog/databricks-plugin" | |
| "@posthog/event-sequence-timer-plugin" | |
| "@posthog/first-time-event-tracker" | |
| "@posthog/geoip-plugin" | |
| "@posthog/github-release-tracking-plugin" | |
| "@posthog/gitub-star-sync-plugin" | |
| "@posthog/hedgehog-mode" | |
| "@posthog/ingestion-alert-plugin" | |
| "@posthog/kinesis-plugin" | |
| "@posthog/maxmind-plugin" | |
| "@posthog/nextjs" | |
| "@posthog/nextjs-config" | |
| "@posthog/nuxt" | |
| "@posthog/pagerduty-plugin" | |
| "@posthog/piscina" | |
| "@posthog/plugin-contrib" | |
| "@posthog/plugin-unduplicates" | |
| "@posthog/react-rrweb-player" | |
| "@posthog/rrdom" | |
| "@posthog/rrweb" | |
| "@posthog/rrweb-player" | |
| "@posthog/rrweb-record" | |
| "@posthog/rrweb-snapshot" | |
| "@posthog/rrweb-utils" | |
| "@posthog/sendgrid-plugin" | |
| "@posthog/siphash" | |
| "@posthog/snowflake-export-plugin" | |
| "@posthog/taxonomy-plugin" | |
| "@posthog/twitter-followers-plugin" | |
| "@posthog/twilio-plugin" | |
| "@posthog/url-normalizer-plugin" | |
| "@posthog/variance-plugin" | |
| "@posthog/web-dev-server" | |
| "@posthog/wizard" | |
| "@postman/aether-icons" | |
| "@postman/csv-parse" | |
| "@postman/final-node-keytar" | |
| "@postman/mcp-ui-client" | |
| "@postman/node-keytar" | |
| "@postman/pm-bin-linux-x64" | |
| "@postman/pm-bin-macos-arm64" | |
| "@postman/pm-bin-macos-x64" | |
| "@postman/pm-bin-windows-x64" | |
| "@postman/postman-collection-fork" | |
| "@postman/postman-mcp-cli" | |
| "@postman/postman-mcp-server" | |
| "@postman/pretty-ms" | |
| "@postman/secret-scanner-wasm" | |
| "@postman/tunnel-agent" | |
| "@postman/wdio-allure-reporter" | |
| "@postman/wdio-junit-reporter" | |
| "@quick-start-soft/quick-document-translator" | |
| "@quick-start-soft/quick-git-clean-markdown" | |
| "@quick-start-soft/quick-markdown" | |
| "@quick-start-soft/quick-markdown-compose" | |
| "@quick-start-soft/quick-markdown-image" | |
| "@quick-start-soft/quick-task-refine" | |
| "@seung-ju/next" | |
| "@seung-ju/openapi-generator" | |
| "@seung-ju/react-hooks" | |
| "@seung-ju/react-native-action-sheet" | |
| "@strapbuild/react-native-date-time-picker" | |
| "@strapbuild/react-native-perspective-image-cropper" | |
| "@strapbuild/react-native-perspective-image-cropper-2" | |
| "@strapbuild/react-native-perspective-image-cropper-poojan31" | |
| "@trigo/atrix" | |
| "@trigo/atrix-acl" | |
| "@trigo/atrix-elasticsearch" | |
| "@trigo/atrix-mongoose" | |
| "@trigo/atrix-orientdb" | |
| "@trigo/atrix-postgres" | |
| "@trigo/atrix-pubsub" | |
| "@trigo/atrix-redis" | |
| "@trigo/atrix-soap" | |
| "@trigo/bool-expressions" | |
| "@trigo/eslint-config-trigo" | |
| "@trigo/fsm" | |
| "@trigo/hapi-auth-signedlink" | |
| "@trigo/jsdt" | |
| "@trigo/keycloak-api" | |
| "@trigo/node-soap" | |
| "@trigo/pathfinder-ui-css" | |
| "@trigo/trigo-hapijs" | |
| "@zapier/ai-actions" | |
| "@zapier/ai-actions-react" | |
| "@zapier/babel-preset-zapier" | |
| "@zapier/browserslist-config-zapier" | |
| "@zapier/eslint-plugin-zapier" | |
| "@zapier/mcp-integration" | |
| "@zapier/secret-scrubber" | |
| "@zapier/spectral-api-ruleset" | |
| "@zapier/stubtree" | |
| "@zapier/zapier-sdk" | |
| "asyncapi-preview" | |
| "atrix" | |
| "atrix-mongoose" | |
| "axios-builder" | |
| "bool-expressions" | |
| "bytecode-checker-cli" | |
| "calc-loan-interest" | |
| "capacitor-plugin-apptrackingios" | |
| "capacitor-plugin-purchase" | |
| "capacitor-plugin-scgssigninwithgoogle" | |
| "capacitor-purchase-history" | |
| "capacitor-voice-recorder-wav" | |
| "claude-token-updater" | |
| "cpu-instructions" | |
| "create-glee-app" | |
| "create-hardhat3-app" | |
| "create-mcp-use-app" | |
| "crypto-addr-codec" | |
| "devstart-cli" | |
| "discord-bot-server" | |
| "dotnet-template" | |
| "esbuild-plugin-eta" | |
| "esbuild-plugin-httpfile" | |
| "eslint-config-trigo" | |
| "eslint-config-zeallat-base" | |
| "ethereum-ens" | |
| "evm-checkcode-cli" | |
| "exact-ticker" | |
| "expo-audio-session" | |
| "gate-evm-check-code2" | |
| "gate-evm-tools-test" | |
| "github-action-for-generator" | |
| "go-template" | |
| "iron-shield-miniapp" | |
| "jan-browser" | |
| "korea-administrative-area-geo-json-util" | |
| "lite-serper-mcp-server" | |
| "manual-billing-system-miniapp-api" | |
| "mcp-use" | |
| "medusa-plugin-announcement" | |
| "medusa-plugin-momo" | |
| "medusa-plugin-product-reviews-kvy" | |
| "medusa-plugin-zalopay" | |
| "n8n-nodes-tmdb" | |
| "open2internet" | |
| "orbit-boxicons" | |
| "orbit-nebula-draw-tools" | |
| "orbit-nebula-editor" | |
| "orbit-soap" | |
| "poper-react-sdk" | |
| "posthog-docusaurus" | |
| "posthog-node" | |
| "posthog-plugin-hello-world" | |
| "posthog-react-native" | |
| "posthog-react-native-session-replay" | |
| "react-element-prompt-inspector" | |
| "react-library-setup" | |
| "react-native-use-modal" | |
| "react-native-worklet-functions" | |
| "redux-forge" | |
| "redux-router-kit" | |
| "rollup-plugin-httpfile" | |
| "scgs-capacitor-subscribe" | |
| "scgsffcreator" | |
| "shinhan-limit-scrap" | |
| "skills-use" | |
| "test-foundry-app" | |
| "test-hardhat-app" | |
| "token.js-fork" | |
| "trigo-react-app" | |
| "typeorm-orbit" | |
| "vite-plugin-httpfile" | |
| "web-types-lit" | |
| "zapier-async-storage" | |
| "zapier-platform-cli" | |
| "zapier-platform-core" | |
| "zapier-platform-legacy-scripting-runner" | |
| "zapier-platform-schema" | |
| "zapier-scripts" | |
| "zuper-cli" | |
| "zuper-stream" | |
| ) | |
| echo "==================================================" | |
| echo " Affected NPM Packages Security Checker" | |
| echo "==================================================" | |
| echo "" | |
| echo -e "Scanning under: ${CYAN}${ROOT_DIR}${NC}" | |
| echo "Checking ${#AFFECTED_PACKAGES[@]} potentially vulnerable packages..." | |
| echo "" | |
| echo -e "${YELLOW}$(rand_msg DUNE_SEARCH_MESSAGES)${NC}" | |
| echo "" | |
| echo "Searching for dependency files (yarn.lock, package-lock.json, pnpm-lock.yaml, pnpm-lock.yml, deno.lock, package.json)..." | |
| echo "" | |
| DEP_FILES=() | |
| GLOBAL_FOUND_PACKAGES=() | |
| PROJECTS_WITH_HITS=0 | |
| while IFS= read -r -d '' file; do | |
| DEP_FILES+=("$file") | |
| done < <(find "$ROOT_DIR" -type f \ | |
| \( -name 'yarn.lock' -o -name 'package-lock.json' -o -name 'pnpm-lock.yaml' -o -name 'pnpm-lock.yml' -o -name 'deno.lock' -o -name 'package.json' \) \ | |
| -print0) | |
| if [ "${#DEP_FILES[@]}" -eq 0 ]; then | |
| echo -e "${YELLOW}No dependency files found under ${ROOT_DIR}.${NC}" | |
| echo -e "${YELLOW}The desert is quiet. No worms today.${NC}" | |
| exit 0 | |
| fi | |
| for dep_file in "${DEP_FILES[@]}"; do | |
| echo "--------------------------------------------------" | |
| echo -e "Scanning file: ${CYAN}${dep_file}${NC}" | |
| echo -e "${YELLOW}$(rand_msg DUNE_SEARCH_MESSAGES)${NC}" | |
| found_count=0 | |
| found_packages=() | |
| for package in "${AFFECTED_PACKAGES[@]}"; do | |
| if grep -qF "\"${package}@" "$dep_file" 2>/dev/null || \ | |
| grep -qF "\"${package}\"" "$dep_file" 2>/dev/null || \ | |
| grep -qF "${package}\":" "$dep_file" 2>/dev/null; then | |
| found_packages+=("$package") | |
| GLOBAL_FOUND_PACKAGES+=("$package") | |
| ((found_count++)) | |
| fi | |
| done | |
| if [ "$found_count" -eq 0 ]; then | |
| echo -e "${GREEN}✓ CLEAN - No affected packages found in this file.${NC}" | |
| echo -e "${GREEN}The sand shifts, but no worm answers.${NC}" | |
| else | |
| ((PROJECTS_WITH_HITS++)) | |
| echo -e "${RED}⚠ WARNING - Found ${found_count} affected package(s) in this file:${NC}" | |
| echo "" | |
| for pkg in "${found_packages[@]}"; do | |
| echo -e " ${RED}✗${NC} $pkg" | |
| done | |
| echo "" | |
| msgs_to_print=$(( found_count )) | |
| if [ "$msgs_to_print" -gt 3 ]; then | |
| msgs_to_print=3 | |
| fi | |
| for ((i=0; i<msgs_to_print; i++)); do | |
| echo -e "${RED}$(rand_msg DUNE_HIT_MESSAGES)${NC}" | |
| done | |
| fi | |
| echo "" | |
| done | |
| echo "==================================================" | |
| echo " SUMMARY" | |
| echo "==================================================" | |
| echo "Total dependency files scanned: ${#DEP_FILES[@]}" | |
| echo "Files with hits: $PROJECTS_WITH_HITS" | |
| if [ "${#GLOBAL_FOUND_PACKAGES[@]}" -eq 0 ]; then | |
| echo -e "${GREEN}✓ CLEAN - No affected packages found in any scanned file.${NC}" | |
| echo "" | |
| echo "Your projects do not appear to use any of the ${#AFFECTED_PACKAGES[@]} affected packages (based on simple string matching)." | |
| echo -e "${GREEN}The desert of Arrakis lies still. No worms, no tainted spice.${NC}" | |
| else | |
| UNIQUE_GLOBAL_PACKAGES=$(printf '%s\n' "${GLOBAL_FOUND_PACKAGES[@]}" | sort -u) | |
| UNIQUE_COUNT=$(printf '%s\n' "${UNIQUE_GLOBAL_PACKAGES}" | wc -l | tr -d ' ') | |
| echo -e "${RED}⚠ WARNING - Affected packages detected across your projects.${NC}" | |
| echo "Unique affected packages found: ${UNIQUE_COUNT}" | |
| echo "" | |
| echo "List of unique affected packages found:" | |
| printf ' %s\n' ${UNIQUE_GLOBAL_PACKAGES} | |
| echo "" | |
| echo -e "${YELLOW}Recommendation:${NC}" | |
| echo " Review these packages in each project and consider removing, replacing," | |
| echo " or upgrading them according to security advisories." | |
| echo "" | |
| echo -e "${RED}The worm has been sighted. It is unwise to ignore it.${NC}" | |
| fi | |
| echo "--------------------------------------------------" | |
| DEV_ENV_DIR="${HOME}/.dev-env" | |
| if [ -d "${DEV_ENV_DIR}" ]; then | |
| echo -e "${RED}⚠ Detected directory: ${DEV_ENV_DIR}${NC}" | |
| echo "This path is sometimes created by suspicious tooling (for example via Bun \$\"\$\" mkdir -p \$HOME/.dev-env)." | |
| echo "Inspect its contents and remove it if you did not intentionally create it." | |
| else | |
| echo -e "${GREEN}No ${DEV_ENV_DIR} directory detected.${NC}" | |
| fi | |
| echo "==================================================" | |
| echo "" | |
| echo "Total packages checked: ${#AFFECTED_PACKAGES[@]}" | |
| echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment