Showing posts with label Web App Security. Show all posts
Showing posts with label Web App Security. Show all posts

Thursday, May 14, 2026

PyPi & NPM Breach Mini Shai-Halud
Navigation
    Run Express App Security Scan - It's Free. How Many Stars Does Your App Get?

    Verified by Cyber Chief - Source list: NHS England Digital CC-4781 | TanStack postmortem | CISA advisory | Microsoft Security Blog

    Key Takeaways

    Mini Shai-Hulud is a credential-stealing npm and PyPI supply-chain worm active since late April 2026. If your developer machines or CI runners installed a compromised package version from TanStack, Mistral AI, SAP CAP, UiPath, OpenSearch, or Guardrails AI — treat them as compromised and rotate every GitHub, npm, and cloud token immediately.

    • What it is: A worm that runs during npm install, uses a two-stage Bun-bootstrap architecture to execute an obfuscated credential-stealing JS payload, and harvests your credentials.

    • Who’s affected: Teams using SAP CAP, TanStack, Mistral AI, UiPath, OpenSearch, Guardrails AI npm packages — or the PyPI lightning 2.6.2/2.6.3 package — between April 29 and mid-May 2026.

    • Affected packages: The attack compromised four core npm packages used in the SAP Cloud Application Programming Model (CAP), which are critical for building and deploying applications on SAP BTP, affecting approximately 570,000 weekly downloads. On April 29, 2026, four npm packages from the SAP development ecosystem were published in malicious versions, marking the first time the Shai-Hulud worm family has directly targeted the SAP supply chain.

    • First 24-hour action: Check your lockfiles now. If you find a match, rotate all GitHub tokens, npm tokens, and cloud credentials before anything else. If a compromised package version ran on a developer machine or CI runner, all secrets from that environment should be rotated.

    • How it spreads: Stolen GitHub tokens let it publish malicious versions of your own packages and inject GitHub Actions workflows into repos you own. The malicious payload was designed to run on the Bun JavaScript runtime, allowing it to bypass traditional Node.js monitoring tools during the npm install process.

    • Forward-looking: Raider Container Security by Cyber Chief detects this worm’s signature in containerised CI runners.

    This affects all software teams that use PyPi and NPM packages in their apps. But it's huge shift in the threat landscape for SAP customers particularly, as the attack surface for SAP systems has expanded beyond traditional components to include npm packages that can directly impact production credentials and environments.

    I say it's big because of its ability to compromise your developer environments and CI/CD pipelines, potentially affecting enterprise SAP deployments.

    This article is a practical triage and decision guide for engineering leads, not a malware reverse-engineering report, to help software teams assess, recover and get back to shipping new features ASAP.

    What Mini Shai-Hulud Is (And Why You Should Care)

    You opened LinkedIn this morning and saw "Mini Shai-Hulud" trending. Your team uses TanStack. Or Mistral AI. Or one of your SAP build pipelines. Or you have no idea what you use. Either way, the question in your head right now is: do I need to drop everything and deal with this, or can it wait until Monday? Let me give you a straight answer — and then a triage playbook to find out for sure.

    Mini Shai-Hulud is the third major wave of the Shai-Hulud npm worm family. The original worm hit npm in September 2025; Shai-Hulud 2.0 followed in December 2025. Mini Shai-Hulud launched on April 29 2026 — targeting the SAP supply chain for the first time, new territory for this worm family.

    It expanded on May 11–12 2026 to TanStack, Mistral AI, UiPath, OpenSearch, Guardrails AI, and a long tail of smaller ecosystems. Total: 172 packages, 403 malicious versions, roughly 518 million cumulative weekly downloads.

    The core behaviour matters because it changes what you do next. When a developer or CI runner runs npm install on an affected package, a preinstall hook executes before the install completes. That script pulls the Bun JavaScript runtime (Bun isn't monitored by most Node.js security tools) and runs an 11.6–11.7MB obfuscated JavaScript payload.

    The payload harvests credentials, then uses your stolen GitHub tokens to spread, publishing new compromised versions and injecting GitHub Actions workflows across every repo your token can reach.

    I'm not telling you this is impossible to deal with. I'm telling you that it is doable, if you act systematically and in the right order.

    Think of this post as an ER triage guide for your software dev team, particularly if you don't have in-house security expertise:

    • Act now: builds ran with affected packages.

    • Act this week: affected versions are in your lockfiles but nothing ran.

    • Harden & have a coffee: no matches anywhere.

    An abstract visualization depicts interconnected software packages arranged in a network pattern, symbolizing the complexity of npm packages and GitHub tokens. The design hints at the potential risks of compromised packages and supply chain attacks, emphasizing the importance of secure developer environments and validated GitHub tokens.

    Quick “Am I Affected?” Checklist

    Run these checks now:

    1. Search your lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml, requirements.txt, poetry.lock) for these exact strings to identify any compromised package version:

    • mbt@1.2.48

    • @cap-js/sqlite@2.2.2

    • @cap-js/postgres@2.2.2

    • @cap-js/db-service@2.10.1

    • @tanstack/* versions dated April–May 2026

    • @squawk/* any version

    • @mistralai/mistralai@2.2.x

    • mistralai==2.4.6 (PyPI)

    • guardrails-ai==0.10.1 (PyPI)

    • lightning==2.6.2 or lightning==2.6.3 (PyPI — note: this is the lightning umbrella package, not pytorch-lightning, which was not affected)

    1. File system grep under node_modules for large single-line JS files (~11.6–11.7MB) named execution.js, router_runtime.js, router_init.js, or setup.mjs. These obfuscated JavaScript files may be found at the package root and within package tarballs, as these are the files the payload drops.

    2. GitHub repo and branch audit: search your GitHub organisation for public repos whose description matches “A Mini Shai-Hulud has Appeared” or Dune-themed names. Look for branches named dependabout/github_actions/format/setup-formatter or similar — these are injected workflow branches the worm creates using stolen GitHub tokens.

    3. Inspect configuration files such as .vscode/tasks.json and .claude/settings.json in any repo you cloned or opened in VS Code or Claude Code during this period. Look for auto-run tasks, SessionStart hooks, or any malicious modifications that download Bun or execute remote scripts.

    4. Run a lockfile grep one-liner:

    grep -rE "mbt@1\.2\.48|cap-js/sqlite@2\.2\.2|cap-js/postgres@2\.2\.2|cap-js/db-service@2\.10\.1" .
    

    And for PyPI:

    pip show lightning | grep -E "^Version: 2\.6\.[23]$"
    
    1. Check GitHub Actions run logs from April 29 to now for any workflow that ran npm install on the affected packages. If you find one, assume that runner’s environment variables, repository secrets, and github_token were harvested.

    2. Check your npm token list for tokens you don’t recognise — the worm mints new npm publish tokens using OIDC abuse.

    3. Check package caches (such as npm, yarn, or pip caches) for remnants of compromised packages, as these may persist even after removal from lockfiles or node_modules.

    Note: If a compromised package version ran on a developer machine or CI runner, immediately rotate all secrets from that environment, including npm tokens, GitHub tokens, cloud credentials, and Kubernetes service account tokens.

    Decision rule

    Any affected package installed on developer machines, build servers, or GitHub Actions runners between late April 2026 and now means those environments are compromised. Continue to "Immediate Response: 0–24 Hours" now — don't skip ahead to containment.

    What Happened: Campaign Overview and Timeline

    April 29 2026 - The SAP Wave

    The campaign opened with four SAP ecosystem npm packages: mbt@1.2.48 (the Cloud MTA Build Tool), @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, and @cap-js/db-service@2.10.1. This was the first time the Shai-Hulud worm family directly targeted the SAP supply chain — a significant escalation, because SAP build tooling runs in environments that hold production credentials.

    For SAP customers, this highlights the critical importance of security and risk management, as threats targeting SAP environments can have a direct impact on business operations.

    It is essential that SAP customers to monitor for additional compromised packages within the SAP ecosystem to mitigate further risks. The four SAP CAP packages alone had approximately 570,000 weekly downloads at the time of compromise.

    Think about SAP penetration testing if that isn't already part of your SAP security structure.

    May 11–12 2026 - The Broad Expansion

    Two weeks later, TeamPCP dramatically widened the blast radius. The second wave hit:

    • TanStack (React Query, Router, Table, Form, and related packages)

    • Mistral AI's JavaScript SDK

    • UiPath's npm libraries

    • OpenSearch JavaScript clients

    • Guardrails AI

    • Plus a long tail of smaller ecosystems: @squawk, @tallyui, @beproduct, @dirigible-ai, @draftauth/@draftlab, @mesadev, @supersurkhet, @taskflow-corp, @tolka, and @ml-toolkit-ts.

    Cross-Ecosystem: PyPI Packages Hit Too

    Simultaneously, the campaign expanded to PyPI: mistralai==2.4.6, guardrails-ai==0.10.1, and lightning==2.6.2 / lightning==2.6.3. That last one is worth calling out explicitly: lightning (the PyPI umbrella package) was compromised, not pytorch-lightning.

    The pytorch-lightning package is a separate legacy project and was not affected. If your team pins pytorch-lightning, you are not in scope for the PyPI arm of this campaign.

    Scale of breach

    Across all three waves: 172 packages, 403 malicious versions, attributed to TeamPCP. Cumulative weekly downloads reached approximately 518 million — not because 518 million developers ran a compromised install this week, but because these packages underpin major ecosystems installed as deep transitive dependencies worldwide. Supply chain attacks at this scale propagate through packages nobody on your team consciously chose to trust.

    Affected Packages and Where They Run

    Defining "Affected"

    “Affected” means a legitimate library was trojanized for a specific version window, known as a compromised package version. The package itself isn’t malicious — TeamPCP compromised publishing credentials or misconfigured OIDC trusted-publishing rules, then published malicious versions that look identical to legitimate releases. It is crucial to supervise package versions used on developer machines and CI environments to detect and mitigate the use of compromised package versions. Short-lived version windows don’t protect you if your lockfile pinned the malicious version or your build server cached it.

    Typical installation locations

    Developer laptops running VS Code or Claude Code, shared CI runners (GitHub Actions, GitLab CI, CircleCI, Jenkins), internal Docker images built from npm install steps, and SAP-specific build environments using the Cloud MTA Build Tool.

    The SAP npm packages are a particularly sensitive case — the cloud MTA build tool is often run in environments that hold deployment credentials for SAP BTP, which connects directly to production data.

    Environment

    Risk Level

    Examples

    Developer machines

    High

    VS Code workstations, claude code users, local Node.js development

    CI/CD runners

    Critical

    github actions, GitLab CI, Jenkins with Node.js

    Docker build images

    Critical

    Node.js base images, SAP build containers

    SAP build environments

    Critical

    cloud mta build tool images, BTP pipelines

    Your Own Private Registries Are at Risk Too

    Here's the part most teams miss. The worm spreads via stolen npm tokens. If any developer machine or CI runner ran one of the compromised packages, the attacker may now hold npm publish rights to packages your team owns. Audit your own private registries and internal packages for suspicious version bumps, added router_init.js or setup.mjs files. Mini Shai-Hulud spreading to your internal packages — which your customers install — is a much bigger problem than the upstream incident.

    Build Your Blast Radius Inventory

    Before you move to the response phase, spend 30 minutes mapping your exposure. Which services and repos depend on each affected package? Where do those dependencies run — dev laptops only, or shared CI/CD too? Which CI environments hold high-privilege secrets (org-wide GitHub tokens, production deploy keys)? This inventory isn't optional — it determines your rotation priority order in the next section.

    If your team finds compromised packages and needs help scoping the blast radius, talk to my team, we've been mapping and helping our penetration testing as a service clients recover quickly from these incidents.

    How Mini Shai-Hulud Works (In Plain English)

    You don't need to understand malware internals to protect your team. But you do need to understand the kill chain, because each stage tells you what you're rotating and why.

    Stage 1 — The Preinstall Hook

    The worm lives in the package.json of the compromised package, specifically within lifecycle scripts such as the preinstall hook—or in the prepare or optionalDependencies fields pointing to a malicious GitHub repository. When your pipeline or developer machine runs npm install, npm evaluates and executes the preinstall lifecycle script automatically, before processing the rest of the dependency graph and applying security checks. This means the malicious code runs as a side effect of a dependency install that appears completely routine, without requiring you to type anything suspicious.

    Stage 2 — The Bun Bootstrap

    The hook pulls the Bun JavaScript runtime — a deliberate choice. Bun isn't Node.js, so most process monitors and SIEM rules don't flag it. The payload (router_runtime.js, execution.js, router_init.js) runs outside the environment your security tooling was built to watch — 11.6–11.7MB of obfuscated JavaScript that downloads quietly.

    Stage 3 — Credential Harvest

    The payload scans for credentials from various sources, including configuration files (such as AWS/Azure/GCP CLI config files), SSH keys, browser session cookies, Claude Code access tokens (.claude/settings.json), GitHub CLI tokens, and environment variables. An embedded Python script scrapes secrets from GitHub Actions runner memory — capturing things that never touch disk. The payload is specifically designed to harvest credentials like GitHub tokens, npm tokens, and cloud service credentials, and exfiltrate them to a public GitHub repository created by the attacker.

    Stage 4 — Persistence and Spreading

    This is what makes Mini Shai-Hulud a worm rather than just a stealer. Using stolen GitHub tokens, it commits malicious .vscode/tasks.json and injects a claude code session hook into .claude/settings.json in every repo it can reach, ensuring the payload is reactivated each time a new coding session starts. The next developer to open one of those projects re-infects themselves automatically. Stolen npm tokens publish new compromised versions; workflow injection dumps secrets from CI environments it hasn’t directly touched, with exfiltrated data sent to a public GitHub repository created by the attacker.

    Stage 5 — Exfiltration via GitHub

    Stolen data is encrypted with attacker-controlled keys and exfiltrated to attacker-controlled public GitHub repositories — dead-drop repos with descriptions like “A Mini Shai-Hulud has Appeared”. The payload is specifically designed to steal GitHub credentials and secrets, often leveraging package preinstall scripts to extract sensitive information. Attackers may use a validated GitHub token, especially with workflow scope, to dynamically instantiate collectors that enumerate repository secrets via the GitHub API. This is clever operational security: the traffic looks like normal GitHub API calls. Your corporate firewall won’t flag api.github.com as suspicious developer activity. Additionally, public GitHub search can reveal real-time activity and compromised repositories related to the attack, providing valuable cybersecurity insights.

    Think of a SLSA-signed malicious package like a forged passport that passes customs — the signature was real, the contents were poisoned. Provenance tells you where a package was built; it doesn’t tell you the build environment’s credentials were clean. Valid provenance does not guarantee a clean package.

    TeamPCP used two compromise methods: stolen static npm tokens and misconfigured OIDC trusted-publishing rules — letting them publish without direct account access.

    The image depicts an abstract representation of a pipeline or workflow, featuring multiple connection points symbolizing various stages in software development, such as npm install and package publishing. This visual metaphor highlights the complexity of managing developer environments and the potential risks of compromised packages and malicious code within the npm ecosystem.

    What the Payload Tries to Steal

    The scope of what Mini Shai-Hulud harvests is wider than most teams realise. Here’s what it targets by environment, including configuration files (which may contain credentials and API keys) and malicious files that can be placed at the package root directory to facilitate payload execution.

    On Developer Machines

    On developer workstations, the payload goes after: GitHub tokens, SSH keys, browser session cookies, AWS/Azure/GCP CLI config files, Claude Code access tokens (.claude/settings.json), .env files in open project directories, and npm tokens in .npmrc. It may also inject a claude code session hook into .claude/settings.json to ensure persistent execution of malicious payloads at the start of each coding session. Developer machines have broad long-lived access — personal GitHub accounts, multiple org memberships, VPN credentials, local database connections. Configuration files containing credentials and API keys are especially targeted, highlighting the importance of securing these files to prevent unauthorized access. A single infected workstation can expose secrets across a dozen services.

    In CI/CD Pipelines

    In GitHub Actions runners and similar CI environments, the worm targets the default github_token, repository secrets injected as environment variables, cloud credentials used for deployment steps, npm publish tokens, and Kubernetes service account tokens. Attackers may embed a formatter workflow within the CI/CD pipeline, which can facilitate secret exfiltration by automating the extraction and transmission of sensitive data. The embedded Python script scraping runner memory is particularly effective — it captures secrets that were never written to disk and won’t show up in a log audit. However, workflow logs can be used to trace the sequence of automated actions during a malicious workflow execution, potentially revealing security bypasses and compromise steps.

    In Cloud Infrastructure

    Cloud targets: AWS STS credentials, Secrets Manager and Parameter Store values, Azure Key Vault tokens, GCP Secret Manager values, Kubernetes service account tokens, and HashiCorp Vault credentials. The worm also targets SAP cloud MTA build tool credentials — the April 29 SAP npm packages were not a random choice.

    All exfiltrated stolen data is encrypted with attacker-controlled keys before it leaves your environment. Assume everything the payload could access was successfully stolen.

    Immediate Response: 0–24 Hours

    How fast do you have to act? Fast. A compromised GitHub token is live and usable the moment it’s stolen. If you found affected packages in your environment, start here — not with “let’s assess the situation over the next few days.”

    Attackers may disguise malicious commits as routine attempts to update dependencies, using commit messages like "update dependencies" to conceal their intent. Be aware that compromised packages added to your environment may include obfuscated files, altered dependencies, or lifecycle scripts that execute malicious payloads during installation.

    Immediately uninstall any compromised packages and reinstall the last known good versions using the command:

    npm uninstall <package> && npm install <package>@<version> --ignore-scripts. 

    This helps ensure that any malicious code is removed and prevents lifecycle scripts from executing during reinstallation.

    Step 1 - Freeze Releases and Pause Workflows

    Stop new releases that depend on affected packages. Pause GitHub Actions workflows that run npm install. Restrict creation of new npm tokens org-wide while triage is in progress.

    Step 2 - Uninstall and Downgrade the Compromised Packages

    Uninstall malicious versions and reinstall clean pinned versions with --ignore-scripts to prevent any further hook execution:

    npm uninstall mbt && npm install mbt@1.2.47 --ignore-scripts
    npm uninstall @cap-js/sqlite && npm install @cap-js/sqlite@2.2.1 --ignore-scripts
    npm uninstall @cap-js/postgres && npm install @cap-js/postgres@2.2.1 --ignore-scripts
    npm uninstall @cap-js/db-service && npm install @cap-js/db-service@2.10.0 --ignore-scripts
    

    For PyPI: pip install lightning==2.6.1 --ignore-installed. Use --no-deps if you need to avoid re-pulling transitive dependencies.

    Step 3 - Rotate Every Credential on Every Affected Host

    Rotate all of the following on every host that ran a compromised package:

    • GitHub personal access tokens (PATs) and gh auth token

    • npm tokens (both classic and granular access tokens)

    • Cloud credentials: AWS IAM access keys, Azure service principal secrets, GCP service account keys

    • Kubernetes service account tokens if the affected runner had cluster access

    • SSH keys stored on the machine

    • Any API keys or service tokens in .env files

    • SAP cloud credentials if you ran the cloud MTA build tool

    Don't try to assess which credentials "might have been" accessed. The payload scanned broadly — assume it found everything.

    Step 4 - Clean Up the GitHub Footprint

    The worm left traces in your GitHub organisation. Remove them now:

    • Delete branches matching dependabout/* or dependabout/github_actions/format/setup-formatter

    • Delete unknown GitHub Actions workflows added in the last 2–4 weeks

    • Find and delete any public GitHub repository created by the attacker, especially those with the description “A Mini Shai-Hulud has Appeared” or Dune-themed names, as these may have been used as destinations for exfiltrated data

    • Audit for and remove any unauthorized GitHub repositories to maintain codebase integrity and prevent malicious activity

    • Revoke unfamiliar OAuth apps, PATs, and GitHub Apps in your organisation settings

    Step 5 - Check .vscode/tasks.json and .claude/settings.json

    Inspect every repo your team has cloned for malicious auto-run entries. In .vscode/tasks.json, look for tasks that download Bun or run remote scripts with runOn: “folderOpen”. In configuration files such as .claude/settings.json, check for a claude code session hook or SessionStart hooks that curl or execute remote content, as these can ensure persistent reactivation of the payload each time a coding session starts. A developer re-infects themselves just by opening a poisoned project directory.

    Step 6 - Isolate Affected Machines

    Pull affected developer machines and CI runners off sensitive networks. For shared build runners: stop them, snapshot for forensics if needed, and plan to rebuild from a known-good baseline rather than trying to clean in place.

    Step 7 - Notify and Document

    Keep it factual, brief, no speculation. Internal comms template: "

    We identified packages affected by the Mini Shai-Hulud supply chain incident in our [environment]. We are rotating credentials and rebuilding affected environments. No customer data has been confirmed exfiltrated at this time. We expect to restore normal operations by [time]."

    Simultaneously, document: packages and versions found, machines that ran them, credentials rotated, and unauthorised GitHub or cloud activity observed. This is your postmortem record and regulatory evidence.

    Short-Term Containment and Eradication: Days 1–7

    Org-Wide Code Search

    Once the immediate bleeding is stopped, run a thorough org-wide search. Look for .claude/settings.json changes, .vscode/tasks.json changes, and new or modified GitHub Actions workflow files across all repos — not just the ones you know used affected packages. Also, use public GitHub search to identify compromised repositories and monitor real-time activity related to the attack. Search your GitHub organisation for public repos with descriptions matching “A Mini Shai-Hulud has Appeared” or Dune-themed names. This npm worm spreads laterally via injected workflow branches; you may find traces in repos with no direct dependency on the compromised packages.

    Search for router_init.js, setup.mjs, router_runtime.js, and execution.js in your container image build contexts, CI runner caches, and artifact stores. Also grep your GitHub Actions workflow files for curl or wget commands fetching Bun or suspiciously large JavaScript files.

    Rebuild Don't Clean

    Rebuild CI runners and container base images from known-good baselines. Don't try to clean in place — the worm's persistence mechanisms are subtle and you may miss one. Especially important for shared runners.

    Clear npm, yarn, and pnpm caches on all build hosts and developer workstations. Reinstall with pinned versions and --ignore-scripts for security-sensitive builds. Update base Docker images to pull clean dependency versions.

    Tighten GitHub Governance Now

    This step will give you the biggest bang for your buck that will keep paying back in the future. Implement these governance controls in parallel:

    • Require pull request reviews before merging changes to .github/workflows/*.yml

    • Enable branch protection on your main branch

    • Restrict which identities can publish to your npm organisation or internal package registries

    • Review and tighten the OIDC trusted-publishing rules for your npm packages — avoid trusting the entire repository, and instead narrow trust to specific repos and specific workflow file paths to reduce the risk of compromise through misconfigured trust policies

    Document the Scope

    Before you close out the incident, write down the breached packages and versions found, every affected machine and runner, credentials rotated, and unauthorised GitHub or cloud activity observed. Unexpected use of credentials that should now be invalid is a signal that rotation was incomplete.

    Assessing Impact on Developer Machines vs CI/CD

    Why the Distinction Matters

    Not all infections are equal in blast radius. You probably can't rebuild everything simultaneously — so here's how to prioritise.

    Developer laptops and workstants hold broad, long-lived access - secrets and tokens for multiple organisations, personal cloud accounts, VPN credentials, SSH keys for production bastions, years of cached credential files. A single infected workstation exposes secrets across dozens of services.

    The persistence mechanism (.vscode/tasks.json + .claude/settings.json) means the machine keeps re-infecting itself until you rebuild it.

    CI/CD environments are more access-constrained than a developer's personal machine, but hold high-sensitivity secrets: github_token with workflow-modification rights, org-wide deploy keys, production cloud credentials, and Kubernetes service account tokens with cluster-admin scope. The embedded Python script scraping runner memory captures these before they expire.

    Priority Order for Limited Capacity

    If your team can't rebuild everything in parallel, here's the order:

    1. Shared CI/build runners first: these hold org-wide secrets and the most sensitive GitHub Actions permissions. Rebuild and rotate secrets.

    2. High-privilege developer workstations: engineering leads, release engineers, DevOps/platform engineers, anyone with admin-level GitHub or cloud access.

    3. Standard developer workstations: rotate credentials first, rebuild as bandwidth allows.

    4. Any machine where the Python memory-scraper ran: full rotation of every repository secret in any workflow that ran on those machines.

    Hardening GitHub, Tokens, and GitHub Actions Workflows

    Minimise Long-Lived Tokens

    Long-lived GitHub tokens are the fuel this worm runs on. Move toward short-lived OIDC tokens for everything that supports them. For GitHub Actions, configure OIDC for AWS, Azure, and GCP deployments instead of storing long-lived cloud secrets or credentials as repository secrets. Never use bypass_2fa=true. Set token expiry to 30 days or less.

    Control Who Can Modify Workflows

    The most impactful single control you can implement today: require pull request reviews before merging changes to any file in .github/workflows/. Also apply this to package.json scripts - a malicious preinstall hook slipped in via an unreviewed PR is exactly how this npm worm seeds supply chain attacks downstream.

    Your branch protection rules on main should also include a requirement that at least one reviewer approves workflow file changes.

    Tighten npm Trusted-Publisher OIDC Rules

    If your npm packages use trusted publishing, narrow the OIDC trust rules to specific repo names (not wildcards), specific workflow file paths, and specific branch refs (refs/heads/main only). Avoid trusting the entire repository, as this broad trust setting can allow any workflow in any branch to publish, increasing the risk of compromise. Instead, restrict trust to only the specific workflow files and branches required. A rule like “any workflow in any branch of this account can publish” is exactly the misconfiguration this worm exploited.

    Watch Workflow Logs for These Signals

    Set up alerts — or at minimum, periodically grep your GitHub Actions workflow logs — for:

    • Suspicious activity in the workflow log, such as unexpected steps or unauthorized actions, which can reveal the sequence of automated actions and potential security bypasses.

    • Sudden creation of public repositories in your organisation with Dune-themed names or descriptions matching “A Mini Shai-Hulud has Appeared” — the worm’s dead-drop exfiltration signature

    • Workflow runs that download the Bun JS runtime or fetch large JS files via curl

    • format-results artifacts containing unexpectedly large JSON blobs

    • New branches matching dependabout/* patterns

    • Workflow runs that create new npm tokens or push to unfamiliar npm packages

    Audit npm Tokens After Rotation

    Don't stop at rotation. This npm worm mints new npm publish tokens during execution — tokens that persist even after you rotate the originals. Check your npm account settings for unrecognised granular access tokens and revoke them.Improving Dependency and Package Hygiene

    Reduce future supply chain breaches through improved dependency management. Cyber Chief's Raider Container Security module will do this for you on auto-pilot so you can concentrate on keeping your CEO happy by shipping new features on time.

    Improving Dependency and Package Hygiene

    Enforce Lockfiles as Code

    Treat your lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml) as a first-class code artefact. Every lockfile change should go through pull request review — not just the package.json update. A lockfile change that you didn't expect is a red flag. Make this a required check in your CI configuration: if package-lock.json changes in a PR but package.json doesn't, that PR needs explanation.

    Pin Exact Versions for Critical Build Tools

    Broad semver ranges (^2.2.0, ~2.2.0) are convenient until they're not. For critical build tooling, the cloud MTA Build Tool, SAP core packages, GitHub Actions runner images, anything that touches your credentials or your deployment pipeline — pin exact versions.

    The 24–48 hour dependency cooldown window is a realistic policy for most engineering teams: don't install a new minor or patch release of a critical package until 24–48 hours after it's published. That window catches most of the incident reporting for a compromised package release.

    Build an Internal Allowlist for High-Impact Packages

    Maintain an internal allowlist of approved versions for your highest-risk packages — the ones with deep access to secrets or build credentials. Cross-reference it against the known compromised versions from this incident: mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, @cap-js/db-service@2.10.1, and the others in the IOC list. Any npm install that tries to pull a blocked version should fail loud.

    SBOM-Based Automated Blocking

    The manual allowlist works for your direct dependencies. For your full transitive dependency graph — the hundreds of packages that get pulled in because something you use depends on them — you need automation. Cyber Chief's Dependency module generates a live SBOM and automatically flags or blocks known-malicious versions as new incidents are registered. See how Cyber Chief's dependency security module works.

    Securing Containers and Build Environments with Raider Container Security

    Where this npm/PyPi Breach Actually Executes

    Many of the most impactful infections happened inside ephemeral containers. GitHub Actions runners are containers. Dockerised SAP build agents are containers. Any workflow that runs npm install and holds a github_token, cloud deploy credential, or npm publish token is a high-value target.

    The worm runs, harvests, and exfiltrates within the lifetime of a single CI job — the container is gone before most post-hoc log analysis would catch it.

    The image depicts an abstract representation of cloud infrastructure featuring container symbols and security shields, symbolizing the protection of developer environments against threats like compromised packages and malicious code. Elements such as npm tokens and GitHub actions are visually integrated, highlighting the importance of secure package management and development tools in modern software workflows.

    What Raider Detects

    Raider Container Security monitors process behaviour inside those containers in real time. It detects:

    • Unexpected downloads of the Bun JavaScript runtime from within a build step

    • Execution of large obfuscated JavaScript files (router_init.js, execution.js, router_runtime.js)

    • The embedded Python memory-scraping behaviour targeting GitHub Actions runner process memory

    • Unusual outbound connections from build containers to GitHub dead-drop repositories

    • npm token minting operations triggered from within a build step

    When Raider flags one of these behaviours, it terminates the process and alerts your team before exfiltration completes. The difference between "caught mid-execution" and "found out three weeks later when GitHub notified us about unexpected publishes."

    Original Cyber Chief Data Point

    We ran Raider Container Security across customer CI environments scanning for Mini Shai-Hulud signatures across the 172 known compromised packages. [NEEDS REAL DATA] — insert: environments scanned, % where an IOC was present but undetected, most common missed signal (expected: Python memory-scraper inside ephemeral runners).

    Why This Matters for Teams Without a Security Hire

    I'm not telling you that container security is easy. I'm telling you the hard parts — network behaviour baselining, process allow-listing, real-time memory-scrape detection — don't have to be manual. Raider operationalises those checks so your team ships, not threat-hunts. You don't need a security team. You need one tool watching the containers.

    Supply chain attacks that execute inside ephemeral CI containers are the hardest class of threat to catch after the fact. When Raider detects "A Mini Shai-Hulud has Appeared" dead-drop traffic from a build container, it terminates the process before exfiltration completes. Setup is a one-time CI integration. Start a free Raider Container Security scan — no credit card, 5 minutes.

    Your Long-Term Strategy: Building Supply Chain Resilience

    The short-term actions get you through this incident. Long-term resilience means not starting from zero the next time. And there will be a next time — Mini Shai-Hulud is the third wave in eight months.

    A Lightweight 3–6 Month Roadmap

    A lightweight supply-chain policy doesn't require a dedicated security team. It requires four things: dependency pinning for critical build tools, npm script review in your PR process, GitHub Actions governance (workflow change reviews, scoped OIDC, branch protection), and a credential rotation playbook you've actually practiced. Add a persistent monitor for public repos in your GitHub organisation with descriptions matching "A Mini Shai-Hulud has Appeared" — the dead-drop naming convention this campaign used will appear in future waves.

    Set a quarterly review cadence for critical build tools — the cloud MTA build tool, SAP CAP core packages, TanStack router, and any package between your CI pipeline and production. Test updates in pre-production monitored by Raider before rolling out. 30 minutes per quarter per package family.

    Maintain SBOM-driven inventory of which services, containers, and developer machines use which versions of your highest-risk packages. When the next supply chain attacks land, you want to be answering "are we affected?" in 10 minutes, not 10 hours.

    Run at least one IR drill per year for npm + GitHub Actions supply chain attacks. Walk through: someone reports a compromised package your team uses. How long to identify affected environments? How long to rotate credentials? How long to rebuild CI runners? The drill reveals gaps before an attacker does. Default Raider Container Security on for every new pipeline.

    Mini Shai-Hulud won't be the last one. There have been three Shai-Hulud waves in eight months. The teams that came out of this in good shape weren't the ones with the biggest security budgets — they were the ones with lockfiles pinned, GitHub Actions hardened, and containerised builds being watched. None of that requires a security hire. All of it requires you to start this week.

    Run a free Raider Container Security scan against your CI runners and build containers to see if Mini Shai-Hulud signatures are present. No credit card required, it takes less than 7 minutes to see results. → Start your free Cyber Chief Express Scan

    Click the green button below to see how Cyber Chief works.


    FAQ

    Do I need to wipe every developer machine that ran npm install on an affected package?

    You're not completely wrong to ask this — the persistence mechanism (.vscode/tasks.json + .claude/settings.json modifications) means cleaning in place is unreliable. For machines with broad access (admins, release engineers, senior devs), rebuild from a known-good baseline. For lower-privilege machines, a full credential rotation plus manual removal of the malicious config files is the minimum viable response.

    Are my GitHub Actions workflows safe if I only used the default github_token?

    No. The default github_token has read/write access to the triggering repository and can be used to modify GitHub Actions workflows. Mini Shai-Hulud specifically uses stolen GitHub tokens to inject new workflow files and add dependabout/ branches. If a runner that held your default github_token ran a compromised package, audit your workflows and branches for injected changes and rotate your token scopes.

    We found no affected versions in our lockfiles — are we in the clear?

    Not entirely. Check three additional things: your npm and Docker build caches (malicious versions can be cached even if your lockfile was later updated), any base container images built during the April 29 – May 14 window that included an npm install step, and your own internal packages for any suspicious version bumps or added setup.mjs / router_init.js files. If all three are clean, you're in good shape — but harden your GitHub Actions workflows anyway.

    Is Mini Shai-Hulud only a JavaScript/npm problem?

    No. The PyPI side of the campaign — mistralai==2.4.6, guardrails-ai==0.10.1, lightning==2.6.2, and lightning==2.6.3 — demonstrates the worm family's cross-ecosystem reach. The lightning package (the PyPI umbrella package, not the older pytorch-lightning legacy package) was specifically compromised. Any Python environment that ran pip install on those versions in the affected window is also in scope.

    How does Raider Container Security fit with other security tools we already use?

    Raider focuses on runtime container behaviour — it watches what processes actually execute inside your build containers and CI runners. It complements rather than replaces SCA tools (which scan static dependency trees) and SAST tools (which analyse source code). The gap Raider fills is ephemeral runtime behaviour: the Bun download that happens mid-build, the memory-scraping Python process that runs and exits before your log-based SIEM would catch it. For supply chain attacks that execute inside CI containers, runtime monitoring is the layer most teams are missing.

    How is Mini Shai-Hulud different from the original Shai-Hulud worm?

    The original Shai-Hulud (September 2025) targeted Node.js ecosystems via npm lifecycle hooks and spread via stolen npm tokens. Shai-Hulud 2.0 (December 2025) added GitHub Actions workflow injection and cross-repo persistence via .vscode/tasks.json. Mini Shai-Hulud adds three new capabilities: SAP supply chain targeting (first time for this family), PyPI cross-ecosystem expansion, and the .claude/settings.json persistence vector targeting Claude Code users. Scale is also larger: 172 packages vs the original worm's ~20.

    Did the malicious packages pass npm provenance and SLSA checks?

    Yes — and this is the part that catches most teams off guard. SLSA provenance and npm trusted publishing tell you that a package was built in a specific, logged environment. They do not tell you that the environment's publishing credentials were clean at build time. In cases where TeamPCP exploited misconfigured npm OIDC trusted-publishing rules, the malicious packages were published through GitHub Actions — so they carry valid provenance attestations. Treat valid provenance as a positive signal, not a guarantee. The correct check is: does the package content match what the maintainer intended to ship?

    Tuesday, May 13, 2025

    Best practice fixes for GraphQL security risks
    Navigation
      Run Express App Security Scan - It's Free. How Many Stars Does Your App Get?

      How WebSockets Work

      WebSockets provide a full-duplex communication protocol that enables real-time data exchange between a client and a server over a single, persistent connection. Unlike traditional HTTP requests, which require a separate connection for each interaction, WebSockets allow arbitrary data to be sent and received continuously, improving performance and responsiveness in web applications.

      WebSocket Protocol and Handshake Process

      The WebSocket protocol starts with an initial handshake, which is an HTTP request upgraded to a WebSocket connection. The process follows these steps:

      1. You initiate a connection to the WebSocket server using an HTTP request with the Upgrade and Connection headers.

      2. The server responds with an HTTP response containing the Upgrade: WebSocket header and a Sec-WebSocket-Accept value derived from the Sec-WebSocket-Key.

      3. Once the WebSocket handshake is complete, a communication channel is established, allowing both the client and the server to send messages asynchronously.

      A typical WebSocket handshake request looks like this:

      GET /chat HTTP/1.1
      Host: example.com
      Upgrade: websocket
      Connection: Upgrade
      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
      Sec-WebSocket-Protocol: chat, superchat
      Origin: https://example.com

      The server returns a response like this:

      HTTP/1.1 101 Switching Protocols
      Upgrade: websocket
      Connection: Upgrade
      Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
      Sec-WebSocket-Protocol: chat

      Websocket vs HTTP

      Both WebSockets and HTTP are widely used communication protocols, but they serve different purposes. HTTP is a request-response protocol, while WebSockets enable full-duplex, real-time communication between a client and a server. Understanding their differences is important for optimizing web applications that require efficient data transmission and secure authentication.

      Feature HTTP WebSockets
      Communication Type Request-Response Full-Duplex
      Connection Handling New connection per request Persistent connection
      Performance Inefficient for real-time communication Efficient for continuous data streaming
      Security Concerns CSRF protection, SQL Injection, XSS Cross-Site WebSocket Hijacking, Man-in-the-Middle
      Supported by Proxy Servers Yes Limited support
      Data Exchange Requires repeated requests Uses WebSocket frames to transmit arbitrary data
      Use Cases Websites, API calls, static content Chat apps, gaming, real-time analytics

      WebSocket Security Considerations

      Secure WebSockets provide real-time bidirectional communication between a client and a server. Unlike traditional HTTP requests, WebSockets establish a persistent WebSocket connection using the WebSocket protocol. However, WebSocket security must be carefully managed to prevent vulnerabilities such as cross-site WebSocket hijacking, man-in-the-middle (MITM) attacks, and SQL injection.

      Authentication and Authorization

      • Authentication Mechanism

      A secure authentication process must be in place to verify the identity of clients connecting to a WebSocket server. Unlike traditional HTTP protocol, WebSockets do not natively support authentication. Therefore, authentication should be handled during the initial handshake using a token-based authentication mechanism such as JWT or OAuth.

      • Authorization Controls

      Even if authentication is implemented, weak authorization can allow other users to access sensitive data. Proper authorization information must be validated on every WebSocket request to prevent unauthorized access. Role-based access control (RBAC) and handle authorization mechanisms should be enforced at the ws server level.

      Secure WebSocket Handshake and Headers

      • Validating the Origin Header

      Unlike standard HTTP headers, WebSockets do not enforce the same origin policy by default. Attackers can exploit this by initiating unauthorized WebSocket connections from malicious domains. To prevent cross-site WebSocket hijacking, the origin header field must be validated during the WebSocket handshake:

      const allowedOrigins = ["https://trusted-domain.com"];
      wss.on("connection", (ws, req) => {
          if (!allowedOrigins.includes(req.headers.origin)) {
              ws.close();
              console.log("Connection rejected due to invalid origin");
          }
      });
      • Customizing WebSocket Headers

      Use customize WebSocket headers such as the Sec-WebSocket-Protocol Header to enforce security policies and restrict access. Additionally, ensure that shared authorization headers are not leaked to unauthorized clients.

      Data Encryption and Secure Communication

      • Using Encrypted WebSocket Connections

      All WebSocket traffic must be encrypted using WebSocket secure (wss://). This prevents man-in-the-middle attacks where attackers intercept WebSocket frames and modify arbitrary data in transit.

      Example of a Secure WebSocket Connection:

      const wss = new WebSocket.Server({ server, secure: true });
      wss.on("connection", function connection(ws) {
          ws.on("message", function incoming(message) {
              console.log("Received: %s", message);
          });
      });

      Preventing Injection Attacks

      • SQL Injection Prevention

      If WebSocket requests interact with a database connection, user inputs must be validated to prevent SQL injection. Instead of concatenating SQL queries, use prepared statements:

      const sql = "INSERT INTO users (username, email) VALUES (?, ?)";
      db.run(sql, [username, email], function (err) {
          if (err) throw err;
      });
      • Cross-Site Scripting (XSS) Mitigation

      If client-side code renders WebSocket traffic, it must be protected from cross-site scripting (XSS). Ensure that WebSocket application messages are sanitized before being displayed to prevent execution of malicious scripts.

      Common WebSocket Vulnerabilities

      If you’re using secure WebSockets in your application, you need to be aware of the security risks they pose. Common WebSocket vulnerabilities can be exploited if proper WebSocket security measures are not in place. Let’s go over the most critical ones and why you should care.

      Lack of Authentication and Authorization

      A WebSocket connection must be properly secured using a strong authentication mechanism and authorization controls. Without these, any client could establish a connection with the WebSocket server, allowing unauthorized users to send data or access restricted resources. Even if authentication is implemented, weak authorization information can enable other users to access sensitive data.

      For example, in a web application, an unauthorized user could intercept chat messages or control real-time financial transactions due to poor handle authorization mechanisms. To mitigate this WebSocket authentication problem, enforce secure authentication using token-based authorization and validate user privileges before processing WebSocket requests.

      Cross-Site WebSocket Hijacking (CSWSH)

      Attackers can exploit cross-site WebSocket hijacking by tricking users into visiting a malicious website that attempts to initiate a WebSocket connection to a trusted server. If the WebSocket application relies on shared authorization headers or cookies, an attacker can establish a WebSocket connection using the victim’s credentials.

      This allows the attacker to steal or manipulate arbitrary data from the application without the user’s knowledge. To prevent this, always validate the origin header field in WebSocket handshake requests and reject connections from untrusted sources.

      Example of a secure WebSocket handshake validation:

      const allowedOrigins = ["https://trusted-domain.com"];
      wsServer.on("connection", (ws, request) => {
          const origin = request.headers["origin"];
          if (!allowedOrigins.includes(origin)) {
              ws.close();
              console.log("Connection rejected due to invalid origin");
          }
      });

      Man-in-the-Middle (MITM) Attacks

      Without proper encryption, WebSocket traffic can be intercepted and modified by an attacker. A man-in-the-middle can eavesdrop on WebSocket frames, manipulate transactions, or inject malicious data into an active session.

      If your application transmits sensitive data over an unencrypted WebSocket protocol (ws:// instead of wss://), you're exposing authentication information, financial transactions, or private messages to attackers.

      Insecure Data Transmission

      Sending sensitive data over an unencrypted WebSocket connection exposes it to data loss, leaks, or unauthorized access. Confidential data like authentication tokens, passwords, and payment details must never be transmitted in plaintext. If an attacker intercepts this data, they can easily hijack accounts or perform identity theft.

      Using encrypted traffic ensures that data remains secure while in transit. This can be achieved through:

      • Enforcing WebSocket secure (wss://)

      • Using strong encryption mechanisms for authentication information

      • Avoiding sending authentication tokens in WebSocket headers

      Denial-of-Service (DoS) Attacks

      Attackers can overload your ws server by opening an excessive number of WebSocket connections or flooding it with large WebSocket frames. This can lead to excessive protocol processing, consuming CPU and memory resources, ultimately causing data loss.

      If your server lacks rate limiting or connection throttling, it becomes an easy target for DoS attacks.

      Code Injection Attacks (XSS and SQL Injection)

      WebSockets handle user input, and if that input isn’t sanitized, attackers can inject malicious scripts or database queries:

      • Cross-Site Scripting (XSS): If client-side code does not properly sanitize user input, attackers can inject JavaScript into WebSocket messages. This could lead to session hijacking, unauthorized data access, or malware execution on modern browsers.

      • SQL Injection: If WebSocket requests interact with a database connection directly without validation, attackers can execute injection attacks such as SQL queries to modify or extract internal record keeping data.

      Unrestricted WebSocket Origin Access

      By default, WebSockets don’t enforce the same-origin policy like traditional HTTP requests.  If the WebSocket server does not validate the origin header, malicious websites can establish unauthorized WebSocket connections. This means an attacker could establish connections from untrusted sources, leading to unauthorized data access or malicious activity on your platform. To prevent this, always restrict WebSocket connections to trusted origins.

      Example of enforcing a strict origin header policy:

      wss.on("connection", function connection(ws, req) {
          if (req.headers.origin !== "https://trusted-site.com") {
              ws.terminate();
          }
      });

      Securing WebSocket Connections

      If you're using WebSocket in your application, security isn't optional—it’s a necessity. WebSockets enable real-time communication but can also expose your system to serious vulnerabilities if not secured properly. Here’s what you need to do to keep your WebSocket connections safe:

      WSS (WebSocket Secure)

      WSS (WebSocket Secure) is the encrypted version of the WebSocket protocol, similar to how HTTPS secures HTTP. It ensures that WebSocket traffic is encrypted, preventing attackers from intercepting or modifying WebSocket frames.

      When a WebSocket connection is established using wss://, the handshake occurs over an encrypted communication channel, protecting against injection attacks, unauthorized access, and data loss.

      To ensure security:

      • Always use wss:// instead of ws:// to prevent man-in-the-middle attacks.

      • Implement TLS encryption to safeguard sensitive data transmitted between the WebSocket client and server.

      • Use the secure wss:// protocol instead of the insecure ws:// transport.

      If an attacker intercepts unencrypted traffic, they can steal authentication information or inject arbitrary data into a session. A secure version of WebSocket connection ensures that sensitive data remains encrypted during transmission.

      • How to Implement Secure WebSockets

        This code block is meant to demonstrate how to implement a secure WebSocket server using Node.js. Specifically, it shows how to configure a WebSocket server to use TLS/SSL encryption, which is essential for secure communication over the wss:// protocol (WebSocket Secure).

        const fs = require("fs");
        const https = require("https");
        const WebSocket = require("ws");
        
        // Creating an encrypted HTTP server
        const server = https.createServer({
            cert: fs.readFileSync("cert.pem"),
            key: fs.readFileSync("key.pem"),
        });
        
        // Setting up a secure WebSocket server
        const wss = new WebSocket.Server({ server });
        
        server.listen(8080, () => {
            console.log("Secure WebSocket server is running on wss://localhost:8080");
        });

      Key Components Explained

      1. fs module:
        Used to read SSL certificate and private key files (cert.pem and key.pem). These are required for setting up a TLS-secured server.

      2. https.createServer():
        Creates an HTTPS server (instead of a plain HTTP server) by providing the certificate and key. This allows for encrypted communication.

      3. WebSocket.Server({ server }):
        Binds the WebSocket server to the secure HTTPS server. This enables support for the wss:// protocol instead of the unencrypted ws://.

      4. server.listen(8080):
        Starts the server on port 8080 and logs a message indicating that the secure WebSocket server is running.

      Preventing Injection Attacks

      Injection attacks occur when an attacker exploits vulnerabilities in the WebSocket connection to send arbitrary data, manipulate WebSocket requests, or compromise sensitive data. Web applications using WebSocket can be susceptible to SQL injection, cross-site scripting (XSS), and other common WebSocket vulnerabilities.

      SQL Injection over WebSockets

      Attackers can exploit WebSocket connections to send arbitrary data and manipulate database queries, potentially gaining unauthorized access to sensitive information. To prevent SQL injection:

      • Always use prepared statements when handling database queries.

      • Validate and sanitize all user inputs before processing them.

      • Validate client input before processing it to prevent SQL injection attacks.

      Secure SQL Query Handling

      const sql = "SELECT * FROM users WHERE username = ?";
      db.get(sql, [username], (err, row) => {
          if (err) throw err;
      });

      Using prepared statements ensures that WebSocket application queries cannot be manipulated by arbitrary data from a client.

      XSS Attacks over WebSockets

      Cross-site scripting (XSS) exploits vulnerabilities in client-side code, allowing attackers to execute malicious scripts on behalf of other users. To mitigate XSS risks:

      • Use JSON.parse() to safely process incoming JSON data.

      • Sanitize all user inputs to prevent script injection.

      Validating Client and Server Data

      Ensuring that data exchanged between the client and the server is valid is crucial for maintaining websocket security.

      Ensuring Data Integrity

      • Use strong authentication mechanisms to verify websocket requests before processing them.

      • Encrypt websocket frames to prevent unauthorized data modification.

      • Implement internal record keeping to log and monitor suspicious activity.

      Origin Header Validation

      • The Origin header field should be validated in the websocket handshake to determine the host of the websocket connection.

      • Enforce a secure version of the WebSocket protocol (Sec-WebSocket-Protocol) to ensure strict origin validation.

      • Implement a whitelist of authorized domains to prevent cross-site WebSocket hijacking.

      • Secure authentication should be performed using a combination of authentication information and ticket-based authentication mechanisms.

      Best Practices for Data Validation

      • Enforce input validation on the server before processing WebSocket frames.

      • Strip out HTML or JavaScript code to prevent cross-site scripting.

      • Ensure all client-side code is properly sanitized before rendering messages.

      Example of Secure Data Handling:

      function sanitizeInput(input) {
          return input.replace(/<[^>]+>/g, ""); // Removes HTML tags
      }
      
      wss.on("message", (msg) => {
          const safeMessage = sanitizeInput(msg);
          console.log("Received sanitized message:", safeMessage);
      });

      Explanation and Context:

      1. Function: sanitizeInput(input)

      • Purpose: It removes any HTML tags from the user input.

      • How: It uses a regular expression / <[^>]+> /g to match and strip out any HTML-like content.

      • Why: To prevent users from injecting potentially malicious scripts (e.g., <script>alert('XSS')</script>) into the application.

      2. WebSocket Server (wss.on("message", ...))

      • This is part of a WebSocket server implementation, listening for incoming messages from clients.

      • The msg parameter represents the raw message sent by a connected user/client.

      • The input is passed through sanitizeInput() before any further processing.

      Authentication and Authorization

      WebSocket authentication and authorization mechanisms are crucial to restricting access to legitimate users only.

      Ticket-Based Authentication

      • Implement a ticket-based authentication mechanism where a secure token is issued after a successful http request authentication process.

      • The authentication token should be sent as part of the WebSocket headers in the initial handshake to verify the user's identity.

      • Avoid using shared authorization headers across multiple WebSocket connections to prevent unauthorized access.

      • Secure authentication should be managed at both the http server and ws server level to prevent websocket authentication problems.

      • Use proxy servers and caching intermediaries to inspect WebSocket traffic and detect anomalies in real-time.

      Best Practices for Secure Authentication

      • Use token-based authentication instead of relying on shared authorization headers.

      • Avoid storing authentication information in WebSocket headers.

      • Implement secure authentication using JWT tokens or OAuth.

      Example of Token Authentication:

      wss.on("connection", (ws, req) => {
          const token = req.headers["sec-websocket-key"];
          if (!validateToken(token)) {
              ws.close();
              console.log("Unauthorized WebSocket connection attempt");
          }
      });
      • wss.on("connection", ...): Listens for incoming WebSocket connections.

      • req.headers["sec-websocket-key"]: Extracts the sec-websocket-key header from the WebSocket upgrade request.

      • validateToken(token): Calls a function (not shown) to check whether the token is valid.

      • If invalid: Closes the WebSocket connection and logs an unauthorized access attempt.

      By securing WebSocket requests with token authentication, unauthorized access can be prevented.

      Testing and Monitoring

      Securing WebSocket connections requires continuous testing and real-time monitoring to prevent common WebSocket vulnerabilities like cross-site scripting (XSS), SQL injection, and man-in-the-middle attacks.

      Key Security Measures

      1. Use WebSocket Security Testing Tools

        Use tools like Wireshark to detect and monitor authentication flaws, injection vulnerabilities, and insecure WebSocket traffic. Intercept and modify WebSocket headers to test authentication mechanisms.

      2. Monitor WebSocket Traffic for Anomalies

        Log WebSocket requests, detect unusual activity, and implement rate-limiting to prevent DoS attacks. Log and analyze WebSocket frames to identify unauthorized access attempts.

      3. Validate WebSocket Authentication

        Ensure authentication tokens are not exposed in WebSocket headers and that sessions expire correctly. Reject WebSocket handshake attempts without valid authentication information.

      4. Prevent Injection Attacks (SQL Injection & XSS)

        Use prepared statements and data sanitization to protect database connections from malicious queries. Prevent SQL injection by validating input before executing queries.

      5. Enforce CSRF Protection and Origin Restrictions

        Require CSRF tokens, validate Origin headers, and restrict WebSocket connections to trusted domains. Close WebSocket connections from untrusted origins.

        How to secure WebSockets in your app?

        Watch the Cyber Chief on-demand demo to see not only how it can help to keep attackers out, but also to see how you can ensure that you ship every release with zero known vulnerabilities. 

        Cyber Chief has been built to integrate with the workflows of high-growth SaaS teams and that's why it offers:

        • Results from scanning your application for the presence of OWASP Top 10 + SANS CWE 25 + thousands of other vulnerabilities.

        • A detailed description of the vulnerabilities found.

        • A risk level for each vulnerability, so you know which ones to fix first.

        • Best-practice fixes for each vulnerability, including code snippets where relevant.

        • On-Demand Security Coaching from our application security experts to help you patch vulnerabilities in hours, not days.

        Click the green button below to see how Cyber Chief works.


      Best practice fixes for GraphQL security risks
      Navigation
        Run Express App Security Scan - It's Free. How Many Stars Does Your App Get?

        What are Fetch Metadata Headers?

        Fetch Metadata Headers are HTTP request headers that browsers automatically send with cross-origin requests. These headers provide contextual information about how a request was initiated, helping web applications enhance security by determining whether a request is legitimate or potentially malicious. They are primarily used to mitigate cross-origin attacks, such as Cross-Site Request Forgery (CSRF) and Cross-Site Script Inclusion (XSSI).

        The Fetch Site Metadata Security Headers include several headers that provide context about the origin and type of a request to improve security. These include:

        • Sec-Fetch-Site: Indicates the relationship between the requesting and target sites (e.g., same-origin, same-site, cross-site).

        • Sec-Fetch-Mode: Specifies the fetch request mode, such as cors, no-cors, or same-origin.

        • Sec-Fetch-Dest: Identifies the resource type being requested (e.g., document, image, script).

        • Sec-Fetch-User: Indicates whether the request was initiated by a user action (e.g., ?1 for user-initiated).

        Common Challenges of Implementing Sec-Fetch Metadata Security Headers:

        1. Cross-Origin Resource Sharing (CORS) Issues:

          Correctly configuring Sec-Fetch-Site headers in conjunction with CORS policies is complex and can block legitimate cross-origin requests if not handled properly.

        2. Browser Compatibility:

          Older browsers that do not support Sec-Fetch-Site headers can lead to inconsistent security behaviors across different user environments, making it difficult to ensure uniform protection.

        3. False Positives and Negatives:

          Misconfigurations of the Sec-Fetch-Site headers can result in false security alerts, either flagging legitimate requests as suspicious or missing actual threats, creating vulnerabilities.

        4. Impact on User Experience:

          Improper handling of metadata headers can cause legitimate requests to be blocked or fail, leading to poor user experience and disrupted application functionality.

        What is Sec Fetch Site Metadata Security Headers & How to implement it

        The Sec-Fetch-Site security header is a part of the Fetch Metadata Request Headers, a set of security mechanisms introduced to help web applications defend against cross-site request forgery (CSRF), cross-site leaks (XS-Leaks), and other types of cross-origin attacks. The primary function of Sec-Fetch-Site is to inform the server whether an incoming request originates from the same site, a related site (such as a subdomain), or an entirely different site.

        By leveraging this information, your web servers can apply security policies that allow only trusted requests while blocking or challenging suspicious cross-site requests. This helps mitigate attacks where malicious actors attempt to exploit the trust between a website and its users.

        How Sec-Fetch-Site Works

        When a browser makes a resource request, such as a navigation request, fetching an image, script, or other content, it includes the Sec-Fetch-Site header. This header contains a value that indicates the relationship between the request’s origin and the target site:

        • same-origin – The request originated from the same domain (same scheme, hostname, and port). These same-origin requests are generally safe.

        • same-site – The request originated from a same-site registrable domain but a different subdomain.

        • cross-site – The request was made from a completely different site. These cross-origin requests pose security risks.

        • none – The user agent does not include any origin information (e.g., due to sandboxed iframes).

        By examining the Sec-Fetch-Site value, you can enforce security policies to reject unwanted cross-site requests while processing legitimate requests.

        Why is Sec-Fetch-Site Important for Web Security?

        The Sec-Fetch-Site header plays an important role in modern web security by helping prevent various attacks that exploit cross-origin behavior. Here are some key reasons why it is important:

        Cross-Site Request Forgery (CSRF):

        • A malicious site may trick a user into performing actions on another site where they are authenticated.

        • The server can reject cross-site requests, preventing unauthorized actions.

        Cross-Origin Information Leaks (XS-Leaks):

        • Attackers may attempt to extract data from a site using timing attacks.

        • By blocking unauthorized cross-origin requests, metadata request headers help protect sensitive information.

        Enhanced Security for Navigation Requests:

        • A user navigating to a site via a bookmark or direct URL (navigate sec fetch site) is considered safe.

        • A navigation attempt from other websites can be rejected based on the Sec-Fetch-Site cross value.

        Improved Defense Against Supply Chain Attacks:

        • Many sites load third-party resources such as scripts and stylesheets.

        • Server-side validation of Sec-Fetch-Site values helps prevent malicious resource injections.

        How to Implement Sec-Fetch-Site in your Web Applications

        If you're looking to enhance the security of your web application and prevent malicious cross-site requests, implementing the Sec-Fetch-Site security header is a crucial step. This header helps your server determine whether incoming requests originate from the same site, a related site, or a completely different site, allowing you to block potentially harmful cross-origin requests.

        Below, I’ll walk you through how to configure Sec-Fetch-Site across different web servers and programming frameworks, including Nginx, Apache, IIS, Django, PHP, and Java.

        1. Nginx

        To configure Sec-Fetch-Site in Nginx, you need to modify your Nginx configuration file (nginx.conf) and set response headers appropriately. The following configuration ensures that Nginx adds fetch metadata headers to responses, helping to enhance security by indicating how requests should be handled.

        Steps:

        Open your Nginx configuration file

        sudo nano /etc/nginx/nginx.conf

        Add the following lines inside your server block to instruct Nginx to handle fetch metadata headers:

        server {
            listen 80;
            server_name yourdomain.com;
        
            location / {
                add_header Sec-Fetch-Site same-origin always;
                add_header Sec-Fetch-Mode no-cors always;
                add_header Sec-Fetch-Dest document always;
            }
        }

        Save the file and restart Nginx:

        sudo systemctl restart nginx

        2. Apache

        If you're running Apache, you can configure Sec-Fetch-Site headers using the .htaccess file or the main Apache configuration.

        Steps:

        1. Edit your Apache configuration file (httpd.conf) or your site's .htaccess file.

        2. Add the following directive to enforce fetch metadata headers. This configuration ensures that:

          • Requests are restricted to the same origin.

          • The fetch mode is set to no-cors.

          • The destination is specified as a document.

          <IfModule mod_headers.c>
              Header always set Sec-Fetch-Site "same-origin"
              Header always set Sec-Fetch-Mode "no-cors"
              Header always set Sec-Fetch-Dest "document"
          </IfModule>
        3. Restart Apache for the changes to take effect:

          sudo systemctl restart apache2

        This setup helps enhance security by controlling how the browser interacts with resources on the server.

        3. IIS (Internet Information Services)

        For Windows-based servers running IIS, you can configure Sec-Fetch-Site headers using the IIS Manager or by modifying the Web.config file. These headers help enhance security by specifying how a request was initiated.

        Steps:

        1. Using IIS Manager:

          Open IIS Manager and navigate to your site.

          Click on HTTP Response Headers and add a new header manually:

          • Name: Sec-Fetch-Site

          • Value: same-origin

        2. Using Web.config:

          Alternatively, you can edit the Web.config file to include multiple security headers. The following configuration ensures that requests originate from the same site, restricts the fetch mode to no-cors, and sets the fetch destination to document:

          <configuration>
              <system.webServer>
                  <httpProtocol>
                      <customHeaders>
                          <add name="Sec-Fetch-Site" value="same-origin" />
                          <add name="Sec-Fetch-Mode" value="no-cors" />
                          <add name="Sec-Fetch-Dest" value="document" />
                      </customHeaders>
                  </httpProtocol>
              </system.webServer>
          </configuration>

        This ensures that your IIS server applies Fetch Metadata Request Headers, improving security against cross-site request forgeries (CSRF) and speculative execution attacks.

        4. Django

        In Django, you can use middleware to modify HTTP responses before they are sent to the client. The following middleware function ensures that the Sec-Fetch-Site, Sec-Fetch-Mode, and Sec-Fetch-Dest headers are added to each response. These headers enhance security by providing additional context about requests, helping to prevent certain types of attacks such as cross-site request forgery (CSRF).

        Steps:

        1. Open your Django settings.py file and add a middleware function:

          from django.utils.deprecation import MiddlewareMixin
          from django.http import HttpResponse
          
          class FetchMetadataMiddleware(MiddlewareMixin):
              def process_response(self, request, response):
                  response["Sec-Fetch-Site"] = "same-origin"
                  response["Sec-Fetch-Mode"] = "no-cors"
                  response["Sec-Fetch-Dest"] = "document"
                  return response

        5. PHP

        For PHP applications, you can set HTTP security headers directly in your code to enhance security and control how the browser handles requests.

        Steps:

        1. Edit your main entry file (e.g., index.php) and add the following lines at the beginning of the file, before any output is sent to the browser:

          header("Sec-Fetch-Site: same-origin");
          header("Sec-Fetch-Mode: no-cors");
          header("Sec-Fetch-Dest: document");

        These headers instruct the browser to enforce security measures by defining how requests should be fetched:

        • Sec-Fetch-Site: same-origin – Ensures the request comes from the same origin.

        • Sec-Fetch-Mode: no-cors – Restricts the request to be used in a no-CORS context.

        • Sec-Fetch-Dest: document – Specifies that the resource being fetched is a document.

        Make sure to place these header() calls before any HTML or other output to prevent header modification errors.

        6. Java (Spring Boot)

        For Java applications using Spring Boot, you can configure Sec-Fetch-Site headers using a response filter. This filter will ensure that every HTTP response includes security-related headers, helping mitigate cross-site request risks and improving security.

        Steps:

        1. Create a filter class in your Spring Boot project. This filter intercepts all HTTP responses and adds the Sec-Fetch headers.

          import jakarta.servlet.Filter;
          import jakarta.servlet.FilterChain;
          import jakarta.servlet.ServletException;
          import jakarta.servlet.ServletRequest;
          import jakarta.servlet.ServletResponse;
          import jakarta.servlet.http.HttpServletResponse;
          import org.springframework.stereotype.Component;
          
          import java.io.IOException;
          
          @Component
          public class FetchMetadataFilter implements Filter {
              @Override
              public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                      throws IOException, ServletException {
                  HttpServletResponse httpResponse = (HttpServletResponse) response;
                  httpResponse.setHeader("Sec-Fetch-Site", "same-origin");
                ;
          
                  chain.doFilter(request, response);
              }
          }
        2. Register the filter in your Spring Boot application to ensure it applies globally.

        Once this filter is added, every response from your Spring Boot application will automatically include these security headers.

        Best Practices for Using Sec-Fetch-Site

        Use Sec-Fetch-Site Alongside Other Security Measures

        It should complement CSRF tokens, CORS policies, and Content Security Policy (CSP) rules for a multi-layered defense.

        Block Cross-Site Requests by Default

        Unless explicitly necessary, servers should reject cross-site requests to reduce the attack surface.

        Whitelist Trusted Same-Site Requests

        Some requests, like API calls between subdomains, may require a more lenient policy. Servers can allow same-site but still reject cross-site.

        Regularly Monitor and Log Requests

        Keeping logs of requests with Sec-Fetch-Site values can help identify suspicious activity and refine security policies.

        What is Sec-Fetch-Mode Metadata Security Header & How to Implement It?

        The Sec-Fetch-Mode security header is a part of the Fetch Metadata Request Headers, a set of security mechanisms introduced to help web applications defend against cross-site request forgery (CSRF), cross-site leaks (XS-Leaks), and other types of cross-origin attacks. The primary function of Sec-Fetch-Mode is to indicate the mode of the request, specifying how the browser handles it and whether it should be subject to CORS checks.

        How Sec-Fetch-Mode Works

        When a browser makes a resource request, such as a navigation request, fetching an image, script, or other content, it includes the Sec-Fetch-Mode header. This header contains a value that describes the type of request being made:

        • navigate – A top-level navigation request, such as clicking a bookmark or entering a URL in the address bar.

        • no-cors – A request that does not trigger CORS checks, often used for fetching resources like images.

        • cors – A request that requires Cross-Origin Resource Sharing (CORS) handling.

        • same-origin – A request made within the same origin.

        • websocket – A secure WebSocket handshake request.

        By examining the Sec-Fetch-Mode value, the server can enforce security policies to reject unwanted or unexpected requests while allowing legitimate ones.

        Why is Sec-Fetch-Mode Important for Web Security?

        The Sec-Fetch-Mode header plays a crucial role in modern web security by helping prevent various attacks that exploit cross-origin behavior. Here are some key reasons why it is important:

        Preventing Cross-Site Request Forgery (CSRF)

        • A malicious site may trick a user into performing actions on another site where they are authenticated.

        • The server can reject cross-site requests by blocking Sec-Fetch-Mode: cors or no-cors requests from untrusted sources.

        Mitigating Cross-Origin Resource Sharing (CORS) Exploits

        • Attackers may attempt unauthorized API calls or data exfiltration using cross-origin requests.

        • Sec-Fetch-Mode allows the server to detect and reject unauthorized CORS requests.

        Enhancing Content Security Policy (CSP) and Request Filtering

        • Many sites load third-party resources such as scripts and stylesheets.

        • Server-side validation of Sec-Fetch-Mode values helps prevent malicious resource injections.

        How to Implement Sec-Fetch-Mode in Your Web Applications

        If you're looking to enhance the security of your web application and prevent malicious cross-site requests, implementing the Sec-Fetch-Mode security header is a crucial step. Let's explore, how to configure Sec-Fetch-Mode across different web servers and programming frameworks, including Nginx, Apache, IIS, Django, PHP, and Java.

        1. Nginx

        To modify your Nginx configuration and set response headers appropriately, update your nginx.conf file as follows. This configuration ensures that the Sec-Fetch-Mode response header is set to navigate for all requests:

        server {
            listen 80;
            server_name yourdomain.com;
        
            location / {
                add_header Sec-Fetch-Mode navigate always;
            }
        }

        Save the file and restart Nginx:

        sudo systemctl restart nginx

        2. Apache

        Edit your Apache configuration file (httpd.conf) or .htaccess file and add the following directive:

        <IfModule mod_headers.c>
            Header always set Sec-Fetch-Mode "navigate"
        </IfModule>

        Restart Apache:

        sudo systemctl restart apache2

        3. IIS (Internet Information Services)

        To configure the Sec-Fetch-Mode header in IIS (Internet Information Services) on Windows-based servers, you can use IIS Manager or modify the Web.config file. The following Web.config snippet demonstrates how to add the Sec-Fetch-Mode header with a value of "navigate" to all HTTP responses:

        <configuration>
            <system.webServer>
                <httpProtocol>
                    <customHeaders>
                        <add name="Sec-Fetch-Mode" value="navigate" />
                    </customHeaders>
                </httpProtocol>
            </system.webServer>
        </configuration>

        This ensures that IIS includes the Sec-Fetch-Mode header in HTTP responses, which helps you to control how requests are handled by the browser, improving security and request integrity.

        4. Django

        Add Sec-Fetch-Mode headers in your middleware:

        from django.utils.deprecation import MiddlewareMixin
        from django.http import HttpResponse
        
        class FetchMetadataMiddleware(MiddlewareMixin):
            def process_response(self, request, response):
                response["Sec-Fetch-Mode"] = "navigate"
                return response

        The above code is a custom Django middleware that adds the Sec-Fetch-Mode header to responses. This header, part of the Fetch Metadata Request Headers, indicates how a resource is being fetched in this case, set to "navigate", which signals that the request is for navigation (e.g., a new page). By providing this information, the header helps improve security, preventing attacks such as cross-site request forgery (CSRF).

        What this Code Does:

        1. The middleware class FetchMetadataMiddleware inherits from MiddlewareMixin, which allows it to work with Django's middleware system.

        2. The process_response method is called after the view has been processed, and before the response is returned to the client.

        3. Inside process_response, the header Sec-Fetch-Mode is added to the response, with the value "navigate".

        4. Finally, the modified response is returned to the client, which now includes the Sec-Fetch-Mode header.

        This middleware can be added to the MIDDLEWARE setting in Django's configuration to ensure the header is automatically included in all responses.

        5. PHP

        In PHP applications, setting specific headers can help control how browsers interact with your site. The following code snippet sets the Sec-Fetch-Mode header, which specifies the mode of the fetch request made by the browser. This header informs the server about how the resource is being requested, which can improve security and enhance performance

        For PHP applications, set the headers in your code:

        header("Sec-Fetch-Mode: navigate");

        6. Java

        The following code block demonstrates how to create a custom filter in Spring Boot that adds a specific HTTP header (Sec-Fetch-Mode) to outgoing responses. Filters in Spring Boot are used to intercept and modify requests and responses before they reach the servlet or after they leave the servlet. This filter, named FetchMetadataFilter, will modify the response to include a header that specifies the fetch mode as "navigate," which can be used by the browser for security purposes.

        import jakarta.servlet.Filter;
        import jakarta.servlet.FilterChain;
        import jakarta.servlet.ServletException;
        import jakarta.servlet.ServletRequest;
        import jakarta.servlet.ServletResponse;
        import jakarta.servlet.http.HttpServletResponse;
        import org.springframework.stereotype.Component;
        
        import java.io.IOException;
        
        @Component
        public class FetchMetadataFilter implements Filter {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                HttpServletResponse httpResponse = (HttpServletResponse) response;
                httpResponse.setHeader("Sec-Fetch-Mode", "navigate");
                chain.doFilter(request, response);
            }
        }

        Best Practices for Using Sec-Fetch-Mode

        Implementing Sec-Fetch-Mode effectively requires integrating it with other security mechanisms to ensure robust protection against cross-origin attacks while maintaining legitimate functionality. Below are some best practices to follow:

        1. Use Sec-Fetch-Mode Alongside Other Security Measures

        Sec-Fetch-Mode should be part of a multi-layered security strategy, working alongside other measures like CSRF tokens, CORS policies, Content Security Policy (CSP), and the Referrer-Policy header, to effectively prevent cross-origin attacks and strengthen web application security.

        2. Block Cross-Site Requests by Default

        Configure your server to block all cross-site requests by default, allow only necessary cross-origin requests via CORS policies, enforce strict Content Security Policy (CSP) rules, and limit preflight requests to essential headers and methods to minimize security risks.

        3. Whitelist Trusted Same-Site Requests

        To ensure seamless communication between subdomains in applications like microservices, SSO authentication, and multi-front-end APIs, allowlist trusted same-site requests, define clear trusted domains, set precise CORS rules, and implement origin checks to validate requests before processing.

        4. Regularly Monitor and Log Requests

        Regular monitoring, along with best practices like logging requests with metadata headers, setting alerts for unusual behaviors, and periodically reviewing security policies, is essential for early threat detection, adapting to evolving threats, and proactively mitigating risks, even with strong security policies in place.

        What is Sec-Fetch-Dest Metadata Security Header & How To Implement It?

        The Sec-Fetch-Dest header is part of the Fetch Metadata Request Headers, designed to provide web applications with information about the destination of a request. This helps in determining whether the request is legitimate and whether it should be allowed or blocked based on its intended purpose.

        By examining the Sec-Fetch-Dest header, web servers can define security policies to restrict unwanted resource loading from untrusted origins, preventing potential attacks like data theft and malicious script injection.

        How Sec-Fetch-Dest Works

        When a browser makes a request for a resource (such as an image, script, or a document), it includes the Sec-Fetch-Dest header to indicate the type of resource being requested. The values of Sec-Fetch-Dest help classify the request type, which allows for better security enforcement.

        Common Sec-Fetch-Dest Values

        The Sec-Fetch-Dest header can have the following values, indicating the destination of the resource request:

        • document – The request is for a full-page document.

        • image – The request is for an image.

        • script – The request is for a JavaScript file.

        • style – The request is for a CSS stylesheet.

        • iframe – The request is for embedding content in an iframe.

        • font – The request is for a font file.

        • audio/video – The request is for multimedia resources.

        • websocket – The request is for a WebSocket connection.

        • empty – The request has no specific destination.

        By analyzing the Sec-Fetch-Dest value, servers can enforce security policies, allowing or blocking requests based on their destination type.

        Why is Sec-Fetch-Dest Important for Web Security?

        The Sec-Fetch-Dest header provides several security benefits by allowing servers to determine the intent of a request. Here’s why it’s important:

        Prevents Resource Misuse

        By validating Sec-Fetch-Dest, servers can prevent unauthorized embedding of resources (e.g., blocking requests for script or iframe from untrusted sources).

        Strengthens Cross-Origin Protections

        It helps in enforcing strict cross-origin policies, reducing risks of CSRF and XS-Leaks.

        Blocks Unwanted Data Exfiltration

        Attackers may attempt to load sensitive resources as images or stylesheets. By analyzing Sec-Fetch-Dest, servers can reject such illegitimate requests.

        Protects Against Clickjacking & UI Redress Attacks

        By disallowing iframe embedding (Sec-Fetch-Dest: iframe) from unknown sources, web applications can prevent clickjacking attacks.

        How to Implement Sec-Fetch-Dest in Your Web Application

        To enhance web security, you should configure your server to inspect and enforce Sec-Fetch-Dest policies. Below are implementations for different web servers and frameworks:

        1. Nginx

        The following configuration modifies your Nginx settings to enforce the Sec-Fetch-Dest header for requests. This header is part of the Fetch Metadata Request Headers, used to communicate the type of destination the request is for (e.g., document, image, script). By adding this header, you're improving the security posture of your server by providing more explicit information to mitigate cross-site request forgery (CSRF) and other security threats.

        Here’s how the configuration works:

        1. The server block listens on port 80 for incoming requests.

        2. The location / block applies the header to all requests coming to your site.

        3. The add_header directive ensures that the Sec-Fetch-Dest header is included in every response, with a value of document (which is common for HTML documents).

        4. The always keyword ensures the header is added regardless of the response code.

        Nginx Configuration:

        server {
            listen 80;
            server_name yourdomain.com;
        
            location / {
                add_header Sec-Fetch-Dest document always;
            }
        }

        After updating your configuration, don't forget to restart Nginx to apply the changes:

        sudo systemctl restart nginx

        2. Apache

        The code block you are adding to your .htaccess file or httpd.conf will ensure that the Sec-Fetch-Dest header is always set to "document" in the HTTP responses. This header is part of the Fetch Metadata Request Headers, which are used by modern browsers to provide additional security context about requests. By setting this header, you can help protect your site against certain types of attacks, such as Cross-Site Request Forgery (CSRF)

        Modify the .htaccess file or httpd.conf with the following code:

        <IfModule mod_headers.c>
            Header always set Sec-Fetch-Dest "document"
        </IfModule>

        After making the changes, restart Apache to apply the configuration:

        sudo systemctl restart apache2

        This will apply the header setting to all HTTP responses served by your Apache server, enhancing security by explicitly declaring the destination of fetch requests.

        3. PHP

        To modify your index.php file and place the header("Sec-Fetch-Dest: document"); above the code block with an explanation, you can do it like this:

        <?php
        // The header("Sec-Fetch-Dest: document") is used to specify that the destination of the fetch request is a document.
        // This helps the browser understand the context of the request, potentially optimizing how the resource is handled.
        // It can also be used as part of security policies to control fetch requests.
        
        header("Sec-Fetch-Dest: document");
        
        // Your code block follows here
        ?>

        This ensures that the header is set before any other output, and you provide a brief explanation about its purpose.

        4. Java

        This FetchMetadataFilter is a custom security filter that adds the Sec-Fetch-Dest: document header to HTTP responses. It helps improve security by specifying the type of resource being fetched (in this case, a document) to your browser, reducing the risk of cross-site attacks. The filter is implemented using the Filter interface, and it’s automatically registered as a Spring Bean using the @Component annotation. When the filter is applied, it processes each HTTP response and adds the security header before passing the request and response along the filter chain.

        Create a security filter:

        @Component
        public class FetchMetadataFilter implements Filter {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                HttpServletResponse httpResponse = (HttpServletResponse) response;
                httpResponse.setHeader("Sec-Fetch-Dest", "document");
                chain.doFilter(request, response);
            }
        }

         Best Practices

        To effectively enhance your web application's security, it’s important to implement Sec-Fetch-Dest correctly while integrating it with other security measures. Here are some best practices that will help you maximize its effectiveness while ensuring legitimate requests function smoothly.

        Combine Sec-Fetch-Dest with Other Security Measures like Content Security Policy (CSP) and Cross-Origin Resource Sharing (CORS)

        Sec-Fetch-Dest provides an extra layer of security, but it works best when combined with these mechanisms. CSP helps you to control which external resources can be loaded, protecting against cross-site scripting (XSS) attacks, while CORS ensures that only trusted domains can access your resources. Additionally, implementing CSRF protection using tokens will help prevent unauthorized request forgery attempts.

        Block Untrusted Cross-Site Requests

        A strong security strategy is to deny all cross-origin requests unless they come from explicitly approved sources. You should configure your server to reject any incoming requests with an unexpected Sec-Fetch-Site value (e.g., cross-site) unless they are explicitly needed. This approach limits unauthorized data access and reduces the risk of security breaches caused by external services.

        Allow Only Trusted Destinations

        Use Sec-Fetch-Dest to specify which destinations are permitted for different kinds of requests. For example, your main pages should only allow document requests, ensuring that only legitimate navigation requests are processed. Similarly, scripts and stylesheets should be fetched only from trusted sources to prevent malicious injections, and AJAX calls should be limited to internal APIs or whitelisted services. By enforcing these restrictions, you prevent unauthorized script execution and data leaks.

        Monitor and Log Requests

        Even with strong security policies in place, constant monitoring is necessary to catch suspicious patterns. You should log request headers, including Sec-Fetch-Dest, Sec-Fetch-Site, and Sec-Fetch-Mode, and use security analytics tools to flag unexpected behaviors—such as excessive failed authentication attempts or a high volume of cross-site requests. Setting up alerts for anomalies will allow you to respond to potential threats before they become critical security risks.

        How to check for Sec Fetch Metadata Security Headers on your app?

        Watch the Cyber Chief on-demand demo to see not only how it can help to keep attackers out, but also to see how you can ensure that you ship every release with zero known vulnerabilities. 

        Cyber Chief has been built to integrate with the workflows of high-growth SaaS teams and that's why it offers:

        • Results from scanning your application for the presence of OWASP Top 10 + SANS CWE 25 + thousands of other vulnerabilities.

        • A detailed description of the vulnerabilities found.

        • A risk level for each vulnerability, so you know which ones to fix first.

        • Best-practice fixes for each vulnerability, including code snippets where relevant.

        • On-Demand Security Coaching from our application security experts to help you patch vulnerabilities in hours, not days.

        Click the green button below to see how Cyber Chief works.