Files
mw-pfeddersheim-workstation/docs/tech/supply-chain-security-2026-03.md
T

24 KiB

description, tags, last_updated, priority
description tags last_updated priority
Supply chain security assessment and comprehensive defense guide for March 2026 incidents (Trivy/TeamPCP, CanisterWorm, GlassWorm).
security
supply-chain
incident-response
hardening
defense-guide
2026-03-23 10

Supply Chain Security Assessment (March 2026)

Scan Results

Check Status Detail
CanisterWorm persistence CLEAN No pgmon service, no ~/.local/share/pgmon/
TeamPCP C2 connection CLEAN No active connection to 45.148.10.212
TeamPCP exfil repos CLEAN No tpcp-docs-* repos found
ICP C2 connection CLEAN No active connection to ICP endpoint
DNS resolution (C2) NOTES scan.aquasecurtiy.org still resolves to 45.148.10.212 (not yet sinkholed)
DNS resolution (ICP) NOTES ICP endpoint resolves via Dfinity boundary nodes (expected - decentralized)

Note on DNS Resolution

C2 domains resolving is expected - they have not been fully sinkholed. The critical check is active connections, which are absent.

Threat Landscape Summary

Trivy/TeamPCP (March 19-22)

  • Tag poisoning on aquasecurity/trivy-action (75 tags)
  • Memory-based credential theft via /proc/<pid>/mem
  • Exfiltration via typo-squatted domain + victim's own GitHub repos
  • Safe version: aquasec/trivy:0.69.3@sha256:0d52a20836526e387157a55f9368d4001c95b77c3855a9010049448106a6b5e0

CanisterWorm (March 20)

  • 66+ malicious npm packages via stolen tokens
  • Self-propagating: harvests npm tokens, republishes victim's packages
  • Persistence: systemd user service (pgmon)
  • C2: ICP blockchain (resistant to takedown)
  • Preceded by "Shai Hulud" worm (2025) - now a recurring pattern
  • Related 2026 campaigns: Shai-Hulud 2.0 (preinstall phase, destructive fallback), SANDWORM_MODE (MCP injection, multi-channel exfil)

GlassWorm (January-March 2026)

  • Invisible Unicode chars (U+FE00-FE0F, U+E0100-E01EF) encode payloads
  • 151+ GitHub repos, 72+ VS Code/Open VSX extensions, 400+ total affected packages
  • Commits blend in with realistic surrounding changes (AI-generated)
  • Cannot be detected by visual code review or standard linting
  • Decoder pattern: maps codepoints to byte values, passes to eval(Buffer.from(...))

Defense Technologies (Deep Research Findings)

Layered Detection Architecture

Layer 1 (Preventive): Workflow Policy + SHA Pinning + OIDC
Layer 2 (Preventive): npm Hardening + Token Scoping + Script Sandboxing
Layer 3 (Detective):  Runtime Monitoring (eBPF: Falco/Tetragon/Tracee)
Layer 4 (Detective):  Unicode Scanning + Pre-commit Hooks
Layer 5 (Detective):  SBOM + Vuln Scanning (syft/grype) + Nuclei
Layer 6 (Detective):  DNS/Network Monitoring + Threat Intel Feeds
Layer 7 (Response):   Credential Rotation + Incident Playbook

1. GitHub Actions Hardening (Trivy/TeamPCP Defense)

SHA256 Digest Pinning

All Actions MUST be pinned to full commit SHA, never tags or branches:

# WRONG - vulnerable to tag poisoning
- uses: aquasecurity/trivy-action@0.69.3

# CORRECT - immutable
- uses: aquasecurity/trivy-action@a12a3943b4151b629d348435e26e7cb35bc0db20

OIDC Token Hardening

  • Enforce short-lived tokens (5-15 min expiration)
  • Restrict token audience to specific cloud providers and repositories
  • Use conditional access policies tied to repository, branch, and environment
  • Disable all long-lived PATs; enforce OIDC for machine accounts

Environment Protection Rules

environments:
  production:
    protection_rules:
      - type: required_reviewers
        reviewers: 2
      - type: wait_timer
        minutes: 30
      - type: restrict_to_deployment_keys

Reusable Workflow Security

  • Store in private repos with explicit access controls
  • Require signed commits for workflow updates
  • Pin calls to specific commits, not branches
  • Audit log all workflow invocations

Action Allowlist Enforcement

# Branch protection or custom CI check
approved_actions:
  - actions/checkout@a1b2c3d4e5f6
  - actions/setup-node@f1b2c3d4e5f6
  - org/internal-action@abcdef123456
enforcement: reject_if_not_in_list

Tag Poisoning Detection

Verify action repos for suspicious signals:

  • Tag has been force-pushed (multiple SHAs for same tag)
  • Repo created < 90 days ago
  • Zero stars and zero forks
  • Unknown or compromised maintainers

Tools: Snyk GitHub Actions Security (auto-scans workflows), SLSA provenance verification.

2. Memory Forensics (TeamPCP /proc/pid/mem Defense)

Attack Vector

/proc/[pid]/mem access allows reading running process memory to extract credentials, tokens, and secrets. TeamPCP targets CI/CD runners holding temporary credentials during workflow execution.

Detection Techniques

Volatility 3 - Post-incident memory analysis:

vol3 -f memory.dump linux.psaux          # Process list with env vars
vol3 -f memory.dump linux.bash            # Command history
# Scan for credential patterns: ghp_*, ghu_*, AWS_*, npm_*

eBPF Real-Time Monitoring - Detect access at syscall level:

// Trace openat syscall for /proc/*/mem access
TRACEPOINT_PROBE(syscalls, sys_enter_openat) {
    char path[256];
    bpf_probe_read_user_str(&path, sizeof(path), (void *)ctx->args[1]);
    if (strstr(&path, "/proc") && strstr(&path, "mem")) {
        events.perf_submit(ctx, &event, sizeof(event));
    }
    return 0;
}

memdump - Capture CI/CD runner memory post-execution, scan for credential remnants before process termination.

Defensive Countermeasures

# Container runtime - deny ptrace capability
securityContext:
  capabilities:
    drop: [SYS_PTRACE]
  readOnlyRootFilesystem: true
  • Deploy runners in VM isolation (not container-only)
  • Enable hardware memory encryption (Intel TME / AMD SEV-SNP)
  • Rotate all credentials immediately post-workflow execution

3. eBPF Runtime Security (Cross-Vector Detection)

Tool Comparison

Tool Strength Best For Enforcement
Falco Rules-based alerting Container environments, broad adoption Alert only (SIGSTOP可选)
Tetragon Kubernetes-native, policy enforcement K8s clusters, tracing policies Kill/block via policy
Tracee Deep syscall tracing, eBPF-only Bare-metal, CI/CD runners Alert + filter

Falco Rules for Supply Chain Attacks

- rule: Unauthorized Process Memory Access
  condition: >
    open and container and
    fd.name glob "/proc/*/mem" or syscall == ptrace
  output: "Unauthorized memory access (user=%user.name cmd=%proc.name file=%fd.name)"
  priority: CRITICAL
  tags: [supply-chain, memory_access]

- rule: Suspicious Env Variable Exfiltration
  condition: >
    syscall == execve and container and
    proc.name in (curl, wget, nc, python) and
    (proc.args contains "GITHUB_TOKEN" or proc.args contains "ghp_" or proc.args contains "npm_")
  priority: CRITICAL
  tags: [supply-chain, credential_exfil]

- rule: Suspicious Systemd Service Creation
  condition: >
    open_write and fd.name glob "*/.config/systemd/user/*" and
    not proc.name in (systemctl, systemd, ansible)
  priority: HIGH
  tags: [supply-chain, persistence]

Tetragon TracingPolicy (Enforcement)

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: block-proc-mem-access
spec:
  kprobes:
  - call: "__fput"
    selectors:
    - matchArgs:
      - index: 0
        operator: "Equal"
        values: ["/proc/*/mem"]
    action: SIGKILL

Tracee for CI/CD Runner Monitoring

tracee \
  --events=open,openat,ptrace,execve \
  --filter='container and (event.args.pathname contains "/proc" and event.args.pathname contains "mem")' \
  --output json \
  --output-file events.json

Workstation Note: eBPF tools require kernel support. For this Arch Linux workstation, bpf package provides headers. Falco can run in agent mode for local monitoring.

4. npm Supply Chain Defense (CanisterWorm Defense)

Lifecycle Script Mitigation

# Global disable (already applied)
npm config set ignore-scripts true

# Per-project override when needed
npm ci --ignore-scripts=false --only=dev   # explicit opt-in

# Node.js policy-based sandboxing (experimental)
node --experimental-policy=policy.json install

Limitation: Shai-Hulud 2.0 uses preinstall phase, bypassing postinstall-focused defenses. --ignore-scripts blocks both, but some legitimate packages require scripts. Use allowlists:

// policy.json - allow specific packages only
{
  "resources": {
    "node_modules/.package-lock.json": {
      "integrity": true
    }
  },
  "dependencies": {
    "package:lodash": true,
    "package:express": true
  }
}

Token Security

Practice Implementation
Granular Access Tokens (GAT) Scope to specific repos + read-only or automation permissions
Token expiration Set max 90 days; automate rotation
Never store in .npmrc Use environment variables or OIDC
Audit tokens quarterly npm token list, revoke unused
MFA enforcement Required for package publish (prevents bypass token abuse)

npm OIDC (Long-Term Fix)

npm OIDC integration is "very hard to compromise" and would "almost completely erase supply-chain attack surface" (Chainguard, 2026). Enables tokenless authentication for package operations.

Systemd Service Monitoring (CanisterWorm pgmon)

# Detect unknown user services
systemctl --user list-units --type=service --all

# Audit service files for anomalies
ls -la ~/.config/systemd/user/

# Check for services with suspicious exec paths
grep -r "ExecStart" ~/.config/systemd/user/ | grep -v "/usr/bin\|/usr/local/bin"

# Monitor service file creation (eBPF Falco rule above)

ICP Blockchain C2 Detection

  • Decentralized C2 via ICP canisters is resistant to traditional takedown
  • Monitor for outbound connections to Dfinity boundary nodes from unexpected processes
  • Network baseline: CI/CD runners should never connect to ICP endpoints
  • Block ICP boundary node IPs at firewall level for non-ICP workloads

Worm Containment

  • socket.dev: Detects malicious packages within 2-5 minutes of publication via differential analysis
  • Monitor all npm packages under org control for unauthorized version publishes
  • Alert on rapid-succession version publishes (1-3 day windows = suspicious)
  • Revoke and rotate tokens immediately if compromise suspected

5. Unicode Attack Defense (GlassWorm Defense)

Understanding the Decoder Pattern

GlassWorm uses this exact decoder signature:

const s = v => [...v].map(w => (
  w = w.codePointAt(0),
  w >= 0xFE00 && w <= 0xFE0F ? w - 0xFE00 :
  w >= 0xE0100 && w <= 0xE01EF ? w - 0xE0100 + 16 : null
)).filter(n => n !== null);
eval(Buffer.from(s(``)).toString('utf-8'));

Detection must target: eval() + Buffer.from() + codepoint arithmetic + apparent empty/whitespace strings.

Detection Tools

# Variation Selectors (VS1-VS16)
grep -rP "[\x{FE00}-\x{FE0F}]" . --exclude-dir=node_modules --exclude-dir=.git

# Ideographic Variation Selectors
grep -rP "[\x{E0100}-\x{E01EF}]" . --exclude-dir=node_modules --exclude-dir=.git

# Combined with decoder pattern
grep -rP "(codePointAt|fromCharCode|Buffer\.from)" . \
  --include="*.js" --include="*.ts" --exclude-dir=node_modules

Python scanner for byte-level detection:

#!/usr/bin/env python3
"""Scan files for GlassWorm Unicode injection patterns."""
import sys, pathlib

VS_RANGES = [(0xFE00, 0xFE0F), (0xE0100, 0xE01EF)]

def scan_file(path):
    content = path.read_bytes()
    hits = []
    for i, b in enumerate(content):
        # Check for multi-byte UTF-8 sequences in VS ranges
        if b >= 0xEF:  # Start of 3-byte UTF-8 (VS range)
            if i + 2 < len(content):
                cp = int.from_bytes(content[i:i+3], 'big')
                for start, end in VS_RANGES:
                    if start <= cp <= end:
                        hits.append((i, hex(cp)))
    return hits

for p in pathlib.Path(sys.argv[1]).rglob('*'):
    if p.suffix in ('.js', '.ts', '.mjs', '.cjs', '.py', '.json'):
        hits = scan_file(p)
        if hits:
            print(f"{p}: {len(hits)} invisible chars found")
            for offset, cp in hits[:5]:
                print(f"  offset {offset}: {cp}")

Git Pre-commit Hook

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: no-invisible-unicode
        name: Block invisible Unicode (GlassWorm defense)
        entry: python3 scripts/unicode-scanner.py
        language: script
        types: [text]

IDE Visibility Configuration

VS Code - Show invisible characters:

{
  "editor.renderWhitespace": "all",
  "editor.unicodeHighlight.ambiguousCharacters": true,
  "editor.unicodeHighlight.invisibleCharacters": true
}

Vim/Neovim:

set list
set listchars+=trail:~,nbsp:␣
" Conceal off for PUA/VS ranges
syntax match GlassWorm "[\uFE00-\uFE0F\uE0100-\uE01EF]" cchar=

VS Code Extension Security

  • Verify extension publisher identity before install
  • Audit extension update history for suspicious version jumps
  • Known malicious: quartz.quartz-markdown-editor v0.3.0 (March 12, 2026)
  • 72+ malicious Open VSX extensions in coordinated campaign
  • Prefer extensions with signed commits and provenance
  • Review extension permissions (workspace access, terminal access = high risk)

Semgrep Rules

rules:
  - id: glassworm-decoder-pattern
    patterns:
      - pattern-either:
          - pattern: |
              eval(Buffer.from($FN(...)).toString(...))
          - pattern: |
              $VAR = $V => [...$V].map($W => ($W = $W.codePointAt(0), ...))
    message: "Potential GlassWorm Unicode decoder pattern detected"
    severity: ERROR
    languages: [javascript, typescript]

6. SLSA Provenance & Sigstore Ecosystem

SLSA Framework (v1.2 Current)

Level Requirement This Workstation
L1 Documented build process Partial (Ansible)
L2 Hosted build platform N/A (local dev)
L3 Hardened build + provenance N/A
L4 Hermetic + reproducible N/A

Applicability: SLSA primarily targets CI/CD builds. For this local workstation, focus on L1 (documented process) and verifying SLSA provenance of consumed packages/artifacts.

Sigstore Components

Component Purpose Tool
cosign Container image signing/verification pacman -S cosign
fulcio Certificate authority (issues certs based on OIDC) Service
rekor Transparency log (immutable record) Service
sigstore-js Node.js client library pnpm add @sigstore/sign
# Verify a container image was signed
cosign verify --certificate-identity=action@github.com \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  aquasec/trivy:0.69.3

# Sign an artifact
cosign sign --key env://COSIGN_PRIVATE_KEY my-image:latest

in-toto Attestations

in-toto provides a framework for verifying the integrity of the software supply chain. Key concepts:

  • Layout: Defines expected steps, authorized functionaries, and inspection rules
  • Attestation: Metadata about a supply chain step (linked to SLSA provenance)
  • Verification: Client-side check that all steps match the layout

Integration with GitHub Actions via slsa-github-generator:

- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
  with:
    attestation-name: my-attestation

7. SBOM Management

Toolchain

# Generate SBOM (CycloneDX format - preferred for security)
syft packages dir:./src -o cyclonedx-json > sbom.json

# Alternative: SPDX format (preferred for license compliance)
syft packages dir:./src -o spdx-json > sbom.spdx.json

# Scan SBOM for vulnerabilities
grype sbom:sbom.json --fail-on high

Format Choice

Format Best For Tooling
CycloneDX Security scanning, vulnerability matching grype, Dependency-Track
SPDX License compliance, legal SPDX tools, FOSSA

Dependency-Track (SBOM Repository)

Centralized SBOM storage and continuous monitoring:

  • Upload SBOMs via API on each build
  • Continuous vulnerability scanning (NVD, OSV, GitHub Advisories)
  • Policy evaluation (fail builds on critical vulns)
  • This workstation: run via Docker for local SBOM management

8. Nuclei Template-Based Scanning

# Install
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# Scan for known supply chain C2 indicators
nuclei -t supply-chain/ -u scan.aquasecurtiy.org

# Scan local git repos for TeamPCP exfil patterns
nuclei -t custom/teampcp-exfil.yaml -target https://github.com/org/repo

# Custom template for C2 domain detection
cat <<'EOF' > nuclei-teampcp.yaml
id: teampcp-c2-detection
info:
  name: TeamPCP C2 Domain
  severity: critical
dns:
  - name: "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "45.148.10.212"
EOF

9. ML-Based & Behavioral Detection (Emerging)

ML Detection Approaches for Supply Chain Attacks

Technique Application Tools/Platforms
Package behavior modeling Detect anomalous postinstall behavior vs. historical baseline socket.dev (differential analysis), EndorLabs
Dependency graph anomaly detection Flag sudden dependency additions, version spikes, or transitive changes Snyk Advisor, Socket.dev risk scores
Code embedding similarity Detect AI-generated commits that mimic project style (GlassWorm evasion) CodeQL ML models, GitHub Advanced Security
Network behavior profiling Detect C2 beacon patterns, unusual outbound from build runners Elastic ML, CrowdStrike Falcon
File system entropy analysis Detect encoded payloads (Unicode steganography, encrypted strings) YARA rules + ML classifiers

Behavioral Detection Patterns

Anomalous Package Behavior (CanisterWorm/Shai-Hulud):

  • Package executes network calls during install (baseline: most packages don't)
  • Package writes files outside node_modules during install
  • Package reads environment variables or .npmrc during install
  • Package spawns child processes during install
  • Detection: compare current package behavior against historical behavior profile

Anomalous Commit Patterns (GlassWorm):

  • Commit modifies only whitespace/Unicode but diff shows zero visual changes
  • Commit timestamp clusters with other suspicious commits across repos (coordinated campaign signal)
  • Commit author style differs from project norm (AI-generated code detection)
  • Detection: git diff --word-diff to catch invisible char changes; commit metadata clustering

Anomalous Build Behavior (TeamPCP):

  • Build process accesses /proc/*/mem (never legitimate in CI)
  • Build process resolves non-whitelisted DNS (tag poisoning C2 indicator)
  • Build process creates outbound connections to non-cdn endpoints
  • Detection: Falco rules (above), DNS query logging, network egress allowlists

Implementation for This Workstation

# Socket.dev CLI - local package risk scoring
npm install -g socket-cli
socket view express    # Risk profile before installing
socket scan ./src      # Scan dependencies for behavioral anomalies

# YARA rule for GlassWorm encoded payloads (high entropy strings)
# Install: pacman -S yara
cat <<'EOF' > rules/glassworm.yar
rule GlassWorm_Unicode_Payload {
  strings:
    $decoder = /codePointAt.*0xFE00|codePointAt.*0xE0100/ ascii
    $eval_buf = /eval\(Buffer\.from/ ascii
    $vs_range = /\xEF\xB8[\x80-\x8F]/  // UTF-8 for U+FE00-FE0F
  condition:
    2 of them
}
EOF
yara -r rules/glassworm.yar ./src

10. DNS & Network Monitoring

Passive DNS Integration

  • Subscribe to Farsight Security or RiskIQ passive DNS feeds
  • Query historical DNS data for infrastructure domains during IR
  • Detect CNAME chains pointing to attacker-controlled servers

Threat Intelligence Feeds

Feed Coverage Integration
URLhaus Known C2 domains API, daily dump
Abuse.ch SSLBL Malicious SSL certificates IP blocklists
VirusTotal Domain reputation API
Custom Typo variants of internal domains Local script

DNS Monitoring for CI/CD

  • Log all DNS queries from runners to SIEM
  • Block non-whitelisted external domains from runners
  • Alert on edit distance < 2 from known infrastructure domains

Hardening Actions

Immediate (Already Applied)

npm config set ignore-scripts true
# 1. Install supply chain security tools
pacman -S syft grype cosign  # SBOM, vuln scan, artifact verify
uv tool install semgrep       # SAST with Unicode rules

# 2. Set up Unicode scanning as pre-commit hook
# (see GlassWorm section above for hook config)

# 3. Configure IDE visibility
# (see GlassWorm section for VS Code/Vim settings)

# 4. Audit systemd user services monthly
systemctl --user list-units --type=service --all

# 5. Network-level C2 blocking (optional)
# Block 45.148.10.212 and ICP boundary nodes if not needed

CI/CD Hardening Checklist

  • Pin all Actions to SHA256 (never tags)
  • Use OIDC over long-lived secrets
  • Block outbound to non-essential domains from runners
  • Run sensitive builds in ephemeral environments
  • Generate and verify SLSA provenance for built artifacts
  • Sign container images with cosign
  • Generate SBOM on every build (syft + grype)
  • Run Nuclei templates against dependencies
  • Enable Unicode scanning in CI pipeline

Detection Patterns

File System IOCs

# CanisterWorm
find ~ -name "pgmon*" -o -name "uv-proxy" -o -name "pglog" 2>/dev/null

# Unknown systemd user services
ls ~/.config/systemd/user/ | grep -v "default.target"

Unicode IOCs (GlassWorm)

# VS1-VS16 range
grep -rP "[\x{FE00}-\x{FE0F}]" . --exclude-dir=node_modules --exclude-dir=.git

# Ideographic Variation Selectors
grep -rP "[\x{E0100}-\x{E01EF}]" . --exclude-dir=node_modules --exclude-dir=.git

# Decoder function pattern
grep -rP "codePointAt.*0xFE00|codePointAt.*0xE0100" . --include="*.js" --include="*.ts"

Network IOCs

# TeamPCP C2
ss -ntu | grep -E "45.148.10.212"
getent hosts scan.aquasecurtiy.org

# ICP C2 (unexpected connections to Dfinity)
ss -ntu | grep -E "icp0\.io|dfinity"

Workstation-Specific Implementation Priority

Priority Action Effort Impact
P0 Pre-commit hook for Unicode scanning 30min Blocks GlassWorm
P0 VS Code invisible char visibility 5min Visual detection
P1 Monthly systemd service audit 10min Detects CanisterWorm
P1 npm config set ignore-scripts true verify 1min Blocks script-based attacks
P2 syft/grype SBOM scanning 1hr setup Continuous vuln monitoring
P2 Nuclei C2 template scanning 30min Network IOC validation
P3 Falco local agent setup 2hr Runtime memory/process monitoring
P3 cosign artifact verification workflow 1hr Build integrity

References

  • Upwind Security: Trivy/TeamPCP analysis
  • EndorLabs: CanisterWorm + SANDWORM_MODE technical analysis
  • Aikido Security: GlassWorm Unicode campaign tracking
  • Unit42 (Palo Alto): Shai-Hulud 2.0 npm supply chain attack
  • Chainguard: npm supply chain hardening and OIDC future
  • CISA: GitHub Actions Security Hardening Guidance
  • Cilium/Tetragon: eBPF Security Enforcement documentation
  • Falco: Runtime security rules and best practices
  • SLSA v1.2: slsa.dev/spec/v1.2
  • Sigstore: sigstore.dev
  • NIST SSDF v1.1: Secure Software Development Framework