@@ -218,12 +218,18 @@ jobs:
218218 PACKAGE_NAME : ${{ steps.dependabot_context.outputs.package_name }}
219219 FROM_VERSION : ${{ steps.dependabot_context.outputs.from_version }}
220220 TO_VERSION : ${{ steps.dependabot_context.outputs.to_version }}
221- MALWARE_WARN_ONLY : ' 1'
222- MALWARE_IOC_PATTERNS : ' ["axios@1\\.14\\.1", "axios@0\\.30\\.4", "plain-crypto-js", "sfrclak\\.com", "@shadanai/openclaw", "@shadanai/[a-z0-9._-]+", "2026\\.3\\.28-2", "2026\\.3\\.28-3", "2026\\.3\\.31-1", "2026\\.3\\.31-2"]'
223- MALWARE_IOC_ALLOWLIST : ' []'
224- MALWARE_UNICODE_ALLOWLIST : ' []'
225- MALWARE_CONFUSABLE_ALLOWLIST : ' []'
226- MALWARE_HEURISTIC_ALLOWLIST : ' []'
221+ MALWARE_WARN_ONLY : >-
222+ 1
223+ MALWARE_IOC_PATTERNS : >-
224+ ["axios@1\\.14\\.1", "axios@0\\.30\\.4", "plain-crypto-js", "sfrclak\\.com", "@shadanai/openclaw", "@shadanai/[a-z0-9._-]+", "2026\\.3\\.28-2", "2026\\.3\\.28-3", "2026\\.3\\.31-1", "2026\\.3\\.31-2"]
225+ MALWARE_IOC_ALLOWLIST : >-
226+ []
227+ MALWARE_UNICODE_ALLOWLIST : >-
228+ []
229+ MALWARE_CONFUSABLE_ALLOWLIST : >-
230+ []
231+ MALWARE_HEURISTIC_ALLOWLIST : >-
232+ []
227233 run : |
228234 sudo apt-get update
229235 sudo apt-get install -y ripgrep jq
@@ -341,9 +347,9 @@ jobs:
341347
342348 is_allowlisted() {
343349 local entry="$1"
344- local -n patterns_ref="$2"
350+ shift
345351 local pattern
346- for pattern in "${patterns_ref[@]} "; do
352+ for pattern in "$@ "; do
347353 [ -n "$pattern" ] || continue
348354 if [[ "$entry" =~ $pattern ]]; then
349355 return 0
@@ -379,10 +385,10 @@ jobs:
379385 scan_with_rg() {
380386 local kind="$1"
381387 local regex="$2"
382- local allowlist_name ="$3"
383- local out_file ="$4"
384- local case_flag="${5:-}"
385- local -n allow_ref="$allowlist_name"
388+ local out_file ="$3"
389+ local case_flag ="$4"
390+ shift 4
391+ local allowlist=("$@")
386392 local hit file rest line text rel entry
387393
388394 if [ ! -s "$file_list0" ]; then
@@ -402,7 +408,7 @@ jobs:
402408 text="${rest#*:}"
403409 rel="${file#.upstream-dependency/}"
404410 entry="${kind}:${rel}:${line}:${text}"
405- if is_allowlisted "$entry" allow_ref ; then
411+ if is_allowlisted "$entry" "${allowlist[@]}" ; then
406412 continue
407413 fi
408414 append_finding "$out_file" "$kind" "$regex" "$rel" "$line" "$text"
@@ -415,12 +421,12 @@ jobs:
415421 # Confusable glyph scan to catch visually similar operator/identifier swaps.
416422 confusable_regex='[\x{FF0F}\x{2215}\x{2044}\x{2217}\x{066D}\x{01C3}\x{FF01}\x{FE57}\x{A789}\x{FF02}\x{FF07}\x{FF40}\x{FE68}\x{FF3C}]'
417423
418- scan_with_rg "unicode" "$unicode_regex" unicode_allowlist "$unicode_jsonl"
419- scan_with_rg "confusable" "$confusable_regex" confusable_allowlist "$confusable_jsonl"
424+ scan_with_rg "unicode" "$unicode_regex" "$unicode_jsonl" "" "${unicode_allowlist[@]} "
425+ scan_with_rg "confusable" "$confusable_regex" "$confusable_jsonl" "" "${confusable_allowlist[@]} "
420426
421427 for ioc_pattern in "${ioc_patterns[@]}"; do
422428 [ -n "$ioc_pattern" ] || continue
423- scan_with_rg "ioc_match" "$ioc_pattern" ioc_allowlist "$ioc_jsonl" "i"
429+ scan_with_rg "ioc_match" "$ioc_pattern" "$ioc_jsonl" "i" "${ioc_allowlist[@]} "
424430 done
425431
426432 heuristic_specs=(
@@ -437,50 +443,52 @@ jobs:
437443 for spec in "${heuristic_specs[@]}"; do
438444 kind="${spec%%::*}"
439445 regex="${spec#*::}"
440- scan_with_rg "$kind" "$regex" heuristic_allowlist "$heuristic_jsonl" "i"
446+ scan_with_rg "$kind" "$regex" "$heuristic_jsonl" "i" "${heuristic_allowlist[@]} "
441447 done
442448
443449 if [ -s "$changed_files_txt" ]; then
444450 while IFS= read -r rel; do
445451 [ -n "$rel" ] || continue
446452 if [[ "$rel" == .github/workflows/* ]]; then
447453 entry="workflow_path_touch:${rel}:0:path"
448- if ! is_allowlisted "$entry" heuristic_allowlist; then
454+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
449455 append_finding "$heuristic_jsonl" "workflow_path_touch" '\.github/workflows/' "$rel" "0" "path-touch"
450456 fi
451457 fi
452458 if [[ "$rel" =~ \.(png|jpg|jpeg|gif|bmp|webp|svg|ico|mp3|mp4|mov|avi|wav)$ ]]; then
453459 entry="steganography_media_change:${rel}:0:media-file-changed"
454- if ! is_allowlisted "$entry" heuristic_allowlist; then
460+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
455461 append_finding "$heuristic_jsonl" "steganography_media_change" 'media-file-change' "$rel" "0" "media-file-changed"
456462 fi
457463 fi
458464 done < "$changed_files_txt"
459465 fi
460466
461467 # Minified/bundled payload heuristic: very long lines outside common build output dirs.
462- while IFS= read -r hit; do
463- file="${hit%%:*}"
464- rest="${hit#*:}"
465- line="${rest%%:*}"
466- text="${rest#*:}"
467- rel="${file#.upstream-dependency/}"
468- if [[ "$rel" =~ ^(dist/|build/|coverage/|vendor/) ]]; then
469- continue
470- fi
471- entry="minified_payload_indicator:${rel}:${line}:${text}"
472- if ! is_allowlisted "$entry" heuristic_allowlist; then
473- append_finding "$heuristic_jsonl" "minified_payload_indicator" '.{1200,}' "$rel" "$line" "$text"
474- fi
475- done < <( [ -s "$file_list0" ] && xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '.{1200,}' < "$file_list0" || true )
468+ if [ -s "$file_list0" ]; then
469+ while IFS= read -r hit; do
470+ file="${hit%%:*}"
471+ rest="${hit#*:}"
472+ line="${rest%%:*}"
473+ text="${rest#*:}"
474+ rel="${file#.upstream-dependency/}"
475+ if [[ "$rel" =~ ^(dist/|build/|coverage/|vendor/) ]]; then
476+ continue
477+ fi
478+ entry="minified_payload_indicator:${rel}:${line}:${text}"
479+ if ! is_allowlisted "$entry" "${heuristic_allowlist[@]}"; then
480+ append_finding "$heuristic_jsonl" "minified_payload_indicator" '.{1200,}' "$rel" "$line" "$text"
481+ fi
482+ done < <(xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '.{1200,}' < "$file_list0" || true)
483+ fi
476484
477485 # Dependency integrity and Dependabot-context checks.
478486 node_vendor_count="$( (rg -n '^(node_modules/|vendor/)' "$changed_files_txt" || true) | wc -l | tr -d ' ' )"
479487 lockfile_count="$( (rg -n '(?:^|/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|npm-shrinkwrap\.json|Gemfile\.lock|go\.sum|Cargo\.lock|poetry\.lock|Pipfile\.lock)$' "$changed_files_txt" || true) | wc -l | tr -d ' ' )"
480488
481489 if [ -n "${TO_VERSION:-}" ] && [ -z "$to_ref" ]; then
482490 entry="ghost_version_or_missing_tag:${TO_VERSION}:0:missing-tag"
483- if ! is_allowlisted "$entry" heuristic_allowlist; then
491+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
484492 append_finding "$heuristic_jsonl" "ghost_version_or_missing_tag" 'missing-tag' "${PACKAGE_NAME:-unknown}" "0" "${TO_VERSION}"
485493 fi
486494 fi
@@ -499,11 +507,11 @@ jobs:
499507 from_semver="$(parse_semver_num "${FROM_VERSION:-}" || true)"
500508 to_semver="$(parse_semver_num "${TO_VERSION:-}" || true)"
501509 if [ -n "$from_semver" ] && [ -n "$to_semver" ]; then
502- read -r fmaj fmin fpat <<< "$from_semver"
503- read -r tmaj tmin tpat <<< "$to_semver"
510+ read -r fmaj fmin _ <<< "$from_semver"
511+ read -r tmaj tmin _ <<< "$to_semver"
504512 if [ "$tmaj" -gt "$fmaj" ] || { [ "$tmaj" -eq "$fmaj" ] && [ "$((tmin - fmin))" -gt 5 ]; }; then
505513 entry="version_jump_anomaly:${PACKAGE_NAME:-unknown}:0:${FROM_VERSION:-}->${TO_VERSION:-}"
506- if ! is_allowlisted "$entry" heuristic_allowlist; then
514+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
507515 append_finding "$heuristic_jsonl" "version_jump_anomaly" 'semver-jump' "${PACKAGE_NAME:-unknown}" "0" "${FROM_VERSION:-}->${TO_VERSION:-}"
508516 fi
509517 fi
@@ -515,13 +523,13 @@ jobs:
515523 if [[ "$from_dep_count" =~ ^[0-9]+$ ]] && [[ "$to_dep_count" =~ ^[0-9]+$ ]]; then
516524 if [ "$to_dep_count" -gt "$((from_dep_count + 8))" ]; then
517525 entry="dependency_count_jump:${PACKAGE_NAME:-unknown}:0:${from_dep_count}->${to_dep_count}"
518- if ! is_allowlisted "$entry" heuristic_allowlist; then
526+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
519527 append_finding "$heuristic_jsonl" "dependency_count_jump" 'dependency-count' "${PACKAGE_NAME:-unknown}" "0" "${from_dep_count}->${to_dep_count}"
520528 fi
521529 fi
522530 if [ "${PACKAGE_NAME:-}" = "axios" ] && [ "$from_dep_count" -gt 0 ] && [ "$to_dep_count" -gt "$((from_dep_count + 2))" ]; then
523531 entry="axios_dependency_count_anomaly:${PACKAGE_NAME:-unknown}:0:${from_dep_count}->${to_dep_count}"
524- if ! is_allowlisted "$entry" heuristic_allowlist; then
532+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
525533 append_finding "$heuristic_jsonl" "axios_dependency_count_anomaly" 'axios-dependency-jump' "${PACKAGE_NAME:-unknown}" "0" "${from_dep_count}->${to_dep_count}"
526534 fi
527535 fi
@@ -541,46 +549,50 @@ jobs:
541549 fi
542550 if [ "${added_count:-0}" -gt 0 ]; then
543551 entry="transitive_dependencies_added:${rel}:0:${added_count}"
544- if ! is_allowlisted "$entry" heuristic_allowlist; then
552+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
545553 append_finding "$heuristic_jsonl" "transitive_dependencies_added" 'transitive-diff' "$rel" "0" "$added_count"
546554 fi
547555 fi
548556 done < "$changed_files_txt"
549557 fi
550558
551559 # Lock checksum/integrity anomaly checks (structure-level, not registry verification).
552- while IFS= read -r hit; do
553- file="${hit%%:*}"
554- rest="${hit#*:}"
555- line="${rest%%:*}"
556- text="${rest#*:}"
557- rel="${file#.upstream-dependency/}"
558- entry="lock_hash_anomaly:${rel}:${line}:${text}"
559- if ! is_allowlisted "$entry" heuristic_allowlist; then
560- append_finding "$heuristic_jsonl" "lock_hash_anomaly" 'integrity-format' "$rel" "$line" "$text"
561- fi
562- done < <( [ -s "$file_list0" ] && xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '"integrity"\s*:\s*"(?!sha(?:1|256|384|512)-)[^"]+"' < "$file_list0" || true )
560+ if [ -s "$file_list0" ]; then
561+ while IFS= read -r hit; do
562+ file="${hit%%:*}"
563+ rest="${hit#*:}"
564+ line="${rest%%:*}"
565+ text="${rest#*:}"
566+ rel="${file#.upstream-dependency/}"
567+ entry="lock_hash_anomaly:${rel}:${line}:${text}"
568+ if ! is_allowlisted "$entry" "${heuristic_allowlist[@]}"; then
569+ append_finding "$heuristic_jsonl" "lock_hash_anomaly" 'integrity-format' "$rel" "$line" "$text"
570+ fi
571+ done < <(xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '"integrity"\s*:\s*"(?!sha(?:1|256|384|512)-)[^"]+"' < "$file_list0" || true)
572+ fi
563573
564574 # Typosquatting indicators from changed dependency metadata.
565- while IFS= read -r hit; do
566- file="${hit%%:*}"
567- rest="${hit#*:}"
568- line="${rest%%:*}"
569- text="${rest#*:}"
570- rel="${file#.upstream-dependency/}"
571- entry="typosquatting_indicator:${rel}:${line}:${text}"
572- if ! is_allowlisted "$entry" heuristic_allowlist; then
573- append_finding "$heuristic_jsonl" "typosquatting_indicator" '(xn--|[-._]{2,}|[^[:ascii:]])' "$rel" "$line" "$text"
574- fi
575- done < <( [ -s "$file_list0" ] && xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '(?i)(xn--[a-z0-9-]+|@[a-z0-9._-]*[._-]{2,}[a-z0-9._-]*|\"[^"]*[^[:ascii:]][^"]*\"\s*:)' < "$file_list0" || true )
575+ if [ -s "$file_list0" ]; then
576+ while IFS= read -r hit; do
577+ file="${hit%%:*}"
578+ rest="${hit#*:}"
579+ line="${rest%%:*}"
580+ text="${rest#*:}"
581+ rel="${file#.upstream-dependency/}"
582+ entry="typosquatting_indicator:${rel}:${line}:${text}"
583+ if ! is_allowlisted "$entry" "${heuristic_allowlist[@]}"; then
584+ append_finding "$heuristic_jsonl" "typosquatting_indicator" '(xn--|[-._]{2,}|[^[:ascii:]])' "$rel" "$line" "$text"
585+ fi
586+ done < <(xargs -0 rg --pcre2 --hidden -nH --no-heading --color=never '(?i)(xn--[a-z0-9-]+|@[a-z0-9._-]*[._-]{2,}[a-z0-9._-]*|\"[^"]*[^[:ascii:]][^"]*\"\s*:)' < "$file_list0" || true)
587+ fi
576588
577589 # Maintainer drift check for npm packages when npm is available.
578590 if command -v npm >/dev/null 2>&1 && [ -n "${PACKAGE_NAME:-}" ] && [ -n "${FROM_VERSION:-}" ] && [ -n "${TO_VERSION:-}" ]; then
579591 from_maint="$(npm view "${PACKAGE_NAME}@${FROM_VERSION}" maintainers --json 2>/dev/null | jq -cS '. // []' 2>/dev/null || true)"
580592 to_maint="$(npm view "${PACKAGE_NAME}@${TO_VERSION}" maintainers --json 2>/dev/null | jq -cS '. // []' 2>/dev/null || true)"
581593 if [ -n "$from_maint" ] && [ -n "$to_maint" ] && [ "$from_maint" != "$to_maint" ]; then
582594 entry="maintainer_drift:${PACKAGE_NAME}:0:${FROM_VERSION}->${TO_VERSION}"
583- if ! is_allowlisted "$entry" heuristic_allowlist; then
595+ if ! is_allowlisted "$entry" "${ heuristic_allowlist[@]}" ; then
584596 append_finding "$heuristic_jsonl" "maintainer_drift" 'npm-maintainers' "${PACKAGE_NAME}" "0" "${FROM_VERSION}->${TO_VERSION}"
585597 fi
586598 fi
0 commit comments