Tuesday, July 14, 2026

OAuth Client ID Spoofing Lets Attackers Validate Stolen Microsoft Entra Credentials

At least two distinct threat actors are weaponizing a novel evasion technique called OAuth client ID spoofing in cloud campaigns, while slipping past telemetry.

The activity allows users to enumerate user accounts and validate stolen credentials in Microsoft Entra ID environments, without ever generating a successful sign-in event that would otherwise alert defenders. And bad actors have begun to exploit this gap to obtain unauthorized access to an organization's cloud services.

"A blind spot in cloud sign-in telemetry: Entra ID returns different error responses depending on whether a supplied OAuth client ID is valid," Proofpoint said in a statement. "Attackers exploit this to infer valid usernames and correct passwords at scale, effectively checking stolen credential lists without logging a successful login."

In other words, the attacks leverage the OAuth client ID, a globally unique identifier (GUID) assigned to applications when requesting access to user data, and is passed as "client_id" in authentication requests. By providing spoofed client IDs, it enables account enumeration without a registered OAuth application and permits attackers to infer both password and account validity without generating a successful sign-in event.

"The Entra sign‑in logs are a primary telemetry source for identifying malicious authentication activity, including user enumeration, password spraying, and initial access attempts," Proofpoint researcher Rachel Rabin said.

Threat clusters like UNK_CustomCloak have been observed spoofing User-Agent strings to orchestrate brute-force campaigns targeting Microsoft Entra ID environments by exploiting a legacy, discontinued first-party application called Windows Live Custom Domains to bypass standard sign-in restrictions and probe user passwords across over 4,000 tenants.

But the latest efforts mark an evolution of this tradecraft by spoofing the OAuth client IDs via HTTP POST requests to Microsoft's OAuth 2.0 token endpoint using the Resource Owner Password Credentials (ROPC) flow. Specifically, this involves supplying a syntactically valid client ID but one that does not correspond to a real application.

In such scenarios, only the application ID is recorded in the Entra sign-in log without a corresponding application name. The response, which contains an Azure Active Directory Security Token Service (AADSTS) error code, can then be used to infer whether the account exists and whether the password is correct without a registered application.

"If the spoofed client ID is not a proper UUIDv4, Entra does not reject the request outright," Proofpoint explained. "Attackers can therefore analyze this error response to identify valid accounts and passwords, despite using malformed client IDs."

"When a spoofed client ID is used, no corresponding application name is recorded in the sign-in log. This means that detections that look for surges against a specific application name may miss this activity entirely, as the field is blank."

Armed with this information, attackers could identify accounts that could be exploited for stealthy access, at the same time making it challenging for defenders to identify suspicious activity.

Proofpoint said it has identified two large campaigns that have independently adopted the technique towards the end of December 2025, indicating the approach is being increasingly incorporated into attacker tradecraft as opposed to being an isolated incident:

  • UNK_pyreq2323 (from January to March 2026), which used more than 700,000 spoofed client IDs from Amazon Web Services (AWS) infrastructure to target more than 1 million accounts across nearly 4,000 tenants, causing lockouts for roughly 28% of targeted users due to failed attempts.
  • UNK_OutFlareAZ (starting Dec 2025), which leveraged Cloudflare infrastructure to target over 2 million users with 3.7 million randomized spoofed application IDs.

Both the campaigns have been observed using valid UUIDs rather than malformed identifiers and demonstrate patterns that align with precompiled username wordlists. That said, while UNK_OutFlareAZ enumerated users alphabetically, UNK_pyreq2323 did not. Another aspect in which they differed was in how the client IDs were spoofed.

UNK_pyreq2323 is said to have modified the trailing digits of a known application ID, and then reused spoofed IDs across up to 12 users. In contrast, UNK_OutFlareAZ generated a unique client ID per request.

"By fragmenting authentication attempts across many fictional applications, activity becomes harder to correlate and may evade per-application detections and rate limiting," Proofpoint said. "Organizations may attempt to mitigate traditional enumeration attacks by applying Conditional Access policies scoped to applications commonly targeted for enumeration. Spoofed client IDs won't trigger CA policies that are scoped to a specific application."



from The Hacker News https://ift.tt/y2n4RhE
via IFTTT

AI Engineer World’s Fair 2026: The Runtime Is Where Agent Trust Is Won

We spent the week at AI Engineer World’s Fair in San Francisco, on stage and on the floor. Here’s what we heard, and where we think it lands for anyone building with agents.

The SDLC is being rebuilt in public

This week at AIE felt like a synthesis of what’s been playing out in developer tools for the last few years, for anyone who’s been watching. The software development lifecycle is reshaping itself into an AI-native SDLC, and the industry is naming the new jobs and developer concerns that come with this rapid transformation.

The proof was in the track list: Evals, Context Engineering, Harness Engineering, Memory, Sandbox & Platform Engineering, Inference, plus a whole thread on “software factories.” Two years ago most of these phrases were far from being thought of as categories. Now each one is a discipline with its own sessions, its own vocabulary, and its own crop of companies on the expo floor built to solve that single problem.

So what were most talks about? A little bit less of “can agents and AI do this,” and more of “given this way of building, what decisions and trade offs do we need to think about?” Evals, loops, harnesses, context, memory, isolation, cost. None of this is brand-new, but it’s all getting a whole new level of mindshare, as developers work out the new shape of creating software with AI. Even the model labs spent much of their stage time on how you build with the model: the integration API, the harnesses, the ergonomics, rather than the model itself. 

The job we care most about: securing where agents run

Of all those emerging disciplines, sandboxing is the one that hit critical mass this year. There was a full track dedicated to sandbox and platform engineering, and the sessions inside it were still working out what a sandbox should even be: full VM, lightweight runtime, Kubernetes, something purpose-built. Talks focused on concerns such as running agentic sandboxes at scale and comparing isolation technologies head to head. 

This is the job Docker showed up to talk about, across three sessions.

Give agents more freedom by giving them less surface

Our EVP of engineering, Tushar Jain, gave the mainstage talk: “Unlock Agent Autonomy: The Runtime for AI-Native Systems.” The actors have changed – agents read and write whole codebases, spawn subagents, install dependencies, and call APIs across laptops, CI, cloud, and org boundaries, often unsupervised. Teams leaning into this shift are moving fast, but most organizations still won’t let agents run autonomously, not because the model isn’t capable, but because trust isn’t there yet. This thinking draws on a concept security researcher Simon Willison has written about, the “lethal trifecta”: any useful agent tends to end up with access to private data, exposure to untrusted content, and the ability to act in the outside world, all three, by design. No prompt or policy doc gets rid of that. The durable fix lives one layer down, at the runtime, which is where we spent the last decade: isolation, network policy, trusted images, credentials. Agents are just the next workload.

An agent doesn’t have to be malicious to be dangerous

Rowan Christmas, a staff product manager at Docker, made the risk concrete. In “YOLO Mode, Safely: microVM Sandboxes for Any Agent,” he ran a coding agent on his own laptop with nothing but read access, and no sandbox or unusual permissions. Within a few minutes it had pieced together a surprising amount about his online banking activity from what it could passively see. A destructive command like rm -rf is the obvious fear, but the mundane can bring risk: read access, plus untrusted content, plus the ability to act, is already enough to do damage. An agent doesn’t have to be malicious to expose you. It just has to be able to see. The alternative Rowan showed puts each session in its own Docker sandbox based on a microVM, with a boundary you define across filesystem, network, and tools. It can run Claude Code, Cursor, Codex, or whatever you’re driving.

Once an agent can install packages, run Docker, and reach the network, which describes most genuinely useful agents, a hardware boundary buys you something you can’t easily bolt on later. And where much of the scale conversation is cloud-first, built for fleets of agents running server-side, Docker’s approach starts first on the laptop the developer already uses, because that’s where most people actually run agents today. (We go deeper on the reasoning in “Why microVMs” and our comparison of sandboxing approaches, including what the isolation costs you, because it isn’t free.)

Nobody’s reviewing what your agents just installed

The third talk covered the tool layer. Jim Clark, a principal software engineer on our MCP team, spoke about “Who Approved That MCP Server? Governing the Tool Layer,” and opened with a line that got knowing laughs: “shadow MCP”. Developers install MCP servers faster than security can review them, and an unvetted server is a direct line to your data. That worry was all over the event, not just our session. Jim’s demo put every server behind one org-managed catalog, vetted, signed, default-deny on anything unapproved, with the policy enforced live on stage.

Where this leaves us

So how does it come together? An agent is only as trustworthy as the boundaries around it, and those boundaries live in three places: what it builds on, where it runs, and what it can reach. Miss any one of them and the other two won’t cover for you. A hardened image dependency is no help if the agent can still read your whole filesystem unsandboxed, and a locked-down sandbox is no help if the agent can call an unvetted MCP server straight out of it.

That was the case Docker made all week: harden what agents build on, isolate where they run, control what they can reach, and govern all three from one place. We think this is the part that has to be solved first, because it’s where AI-native developers will start building the apps of the future.

Further reading: 



from Docker https://ift.tt/AF7aMOK
via IFTTT

Preparedness is the only viable path forward: Introducing Section 1494

We have seen how quickly a compromise can translate into complete system failure across healthcare, manufacturing, and logistics. Ransomware is disabling clinical systems and delaying care. Supply chain intrusions are halting production lines, forcing teams into manual recovery. Add in escalating global conflicts, and standard perimeter defenses or reactive patching cycles are no longer enough. Organizations must prepare proactively, respond to incidents rapidly, and fundamentally harden the systems that power their daily operations. Preparedness is no longer a theoretical exercise; it is mandatory.

IT systems are operating under continuously increasing adversarial pressure. The shift to permanent hybrid and remote work means we now rely on externally reachable control planes, identity systems, and application delivery infrastructure. These systems are now routinely targeted by actors with clear objectives, substantial funding, and the patience to exploit architectural weakness.

Citrix solutions have long provided the foundation for the most resilient and reliable remote work environments across the globe. By centralizing data, securing application delivery, and abstracting the endpoint from the corporate network, these architectures inherently reduce the attack surface and simplify the endpoints. However, protecting these complex, enterprise-grade systems requires you to rigorously harden, carefully configure, and continuously monitor them.

To meet this critical demand, Citrix is announcing the launch of Section 1494: Citrix® Strategic Security Services.

Named in homage to the legacy port that first defined secure remote access, Section 1494 represents an elite group of deeply specialized security architects and incident response experts.

Section 1494 operates far beyond traditional technical support. By embedding directly into customer security operations, these specialists will fundamentally improve how you defend and respond. We do this through:

  • Architectural health checks to find vulnerabilities before attackers do.
  • Hardening workshops to secure your configurations.
  • Remediation roadmaps to build a path to security excellence.
  • Continuous telemetry monitoring for advanced threat detection.
  • Tabletop exercises to stress test your incident response protocols before a crisis hits.

We are also partnering with a premier third-party digital forensics and incident response company to extend our capabilities. This gives us the ability to scale up to hunt threats, analyze forensics, and provide additional services that we have not in the past.

Section 1494 is not just an auditing branch; it is a strategic advisory partnership designed to help our customers navigate the complexities of the modern threat landscape. We approach this mission with humility. We recognize that our own core infrastructure, particularly edge components like NetScaler®, has been a high-value target for both nation-state actors and criminal syndicates. We have seen the tactics, techniques, and procedures (TTPs) firsthand, and we have built Section 1494 to meet them head on.

The mandate for Section 1494 is clear: to operate as the most informed, capable, and risk-aware security practitioners in the industry focused on Citrix technologies. By combining deep product telemetry with expert-led governance and response capabilities, Section 1494 helps you navigate modern cyber threats with confidence, keeping your users secure and productive.

The threats we face globally are immense, but so is our capacity to defend against them. We invite you to engage with Section 1494, and let us help you build a digital workspace that is not only secure by configuration but operationally resilient by design.



from Citrix Blogs https://ift.tt/lFCgsm8
via IFTTT

The serpent’s tongue: Luring the Python out of its den

  • Python's popularity, readable syntax, and extensive third-party library ecosystem make it an attractive target for threat actors seeking to compromise developer devices and infrastructure.  
  • Malicious packages and supply-chain attacks are increasingly common, exploiting the trust built into Python's packaging ecosystem to execute payloads at the moment of installation, without any direct interaction from the victim.  
  • This blog examines the full lifecycle of a Python package, from hosting on repositories such as PyPI or custom web servers, through source and wheel distribution formats, to the final installation into virtual or system-wide Python environments. Each technique is assessed for persistence, supported build methods, and distribution compatibility.  
  • We conclude with practical defensive measures, including dependency auditing tools, version pinning strategies, installation time controls, and general best practices for minimizing supply-chain risk.

The serpent’s tongue: Luring the Python out of its den

Due to the friendly nature of its syntax, extensive capabilities, and wide range of libraries, Python’s adoption by the developer community has been steadily increasing. Both the StackOverflow Developer Survey and the first party package repository PyPi’s download stats indicate rapidly growing usage, especially for data science, AI, and backend projects. Python has a very vibrant community of modules that can be easily installed using various package indexes. Unfortunately, this convenience comes with an additional burden. Malicious packages and supply chain infection are also increasingly common, as threat actors attempt to utilize these modules to infect as many victim devices as possible, abusing the very trust that the community is built upon. GitHub’s 2025 security data highlights the accelerating threat to the software supply chain, noting a 69% year-over-year increase in published malware advisories. Notably for Python developers, 17% of all reviewed advisories in the GitHub Advisory Database are now related to the Pip ecosystem, reflecting a significant targeting of Python-based environments. The threat actor group TeamPCP has also utilized software supply chain attacks, including misuse of Python modules, to compromise Microsoft’s GitHub subsidiary and carry out 20 “waves” of supply chain attacks according to Wired. 

Users often believe that for a malicious payload to be executed they need to directly interact with the infected piece of code (e.g., providing it with a sensitive input, executing its entry point, or importing it to a working project). In reality, Python packages can establish a foothold simply through installation. While analyzing these techniques in detail, we will take a deeper look at the background process of package installation for Python. This will help understand the threat landscape for Python packages, including legitimate components adversaries try to alter for their benefit.

Journey of a Python package 

The serpent’s tongue: Luring the Python out of its den
Figure 1. Layers of Python package installation.

The process of moving a Python package from a remote repository to a local machine involves three distinct layers. While these layers are interconnected, they provide a useful abstraction for understanding the installation process: 

  • Hosting layer: Defines the location where the package is published 
  • Distribution layer: Specifies the file formats supported by the package 
  • Installation layer: Dictates the method of deployment for the package

Hosting packages 

Python packages can be installed from various remote repositories.  

PyPI (Python Package Index): PyPI is the official repository for Python packages. The native package manager, pip, uses PyPI by default. Package details are accessible via a JSON API at “https://pypi.org/pypi/<package-name>/json”. During installation, the PyPI frontend redirects users to “files.pythonhosted.org”, where the actual files are stored. Download URLs are derived from the distribution file name and its blake2b_256 hash. For example:

The serpent’s tongue: Luring the Python out of its den

Version control systems (VCS): Projects hosted on platforms like GitHub or GitLab can be installed directly. This supports open source development through transparent issue tracking. A project can be installed using the following command:

The serpent’s tongue: Luring the Python out of its den

Custom web servers: Any web server with a suitable directory structure can serve as a repository. Packages must be hosted in folders using their normalized names, with all versions grouped together:

The serpent’s tongue: Luring the Python out of its den

To use a custom repository, pip must be instructed to use a different index URL:

The serpent’s tongue: Luring the Python out of its den

Alternatively, users can provide an extra index URL to search multiple repositories:

The serpent’s tongue: Luring the Python out of its den

Configuration and environment variables: Index URLs can be specified in pip configuration files at three levels, global (system-wide), user (specific to a user), or site (specific to an environment). The PIP_CONFIG_FILE environment variable can also point to a custom configuration. Additionally, any pip command line argument can be converted into an environment variable using the PIP_<UPPER_LONG_NAME> format, such as PIP_FIND_LINKS.

Distributing Packages 

Independent of the hosting layer, Python packages are published in two primary formats: 

  • Source Distributions (sdist): These come in a packed .tar.gz format. They contain the full source code and build instructions, requiring the package to be built on the user's workstation before installation. 
  • Wheel Distributions: These come in a pre-built .whl format. They are ready to be deployed immediately, providing a faster and more robust installation process. Despite having .whl extension, these distributions use same format as the .zip files. 

Source distributions rely on build instructions, typically written as either a “setup.py” or “pyproject.toml” file. While “pyproject.toml” is the modern, preferred format due to its transparency and support for various backends, “setup.py” is a standalone script that uses Setuptools. A critical security concern is that “setup.py” executes automatically during installation or download, allowing for the execution of arbitrary code.

The serpent’s tongue: Luring the Python out of its den
Table 1. Brief comparison between “setup.py” and “pyproject.toml”.

Installing packages 

Distribution format and target environment are the main parameters of the installation layer. Distribution format determines if the build process will take place on the user computer. Depending on the target environment used, accessibility of the package will differ after installation. 

Besides system-wide deployments, use of virtual environments are very common. Virtualization of Python environment isolates packages and their versions per deployment. It prevents version conflicts between different software, which are relying on the same set of dependencies with varying versions. Isolation occurs mainly on the package and binary level. Once activated, a virtual environment is treated as a separate Python site, sharing the same file system and network interfaces, but with its own binary and package library. Therefore, we cannot consider this type of virtualization containerized. 

Use of virtual environments provides convenient management for package dependencies. Direct dependencies of a Python package is handled in various locations. Within source distributions, direct dependencies can be found on: 

  • “setup.py”, the setup function contains an install_requires parameter, where dependencies can be listed
  • “pyproject.toml”, under “projects” section, dependencies parameter lists required packages 
  • “requirements.txt” file contains a list of dependencies 
  • “Pipfile”, under packages section 

After package is built, dependencies are listed in the “METADATA” file under “.dist-info” folder within wheel distribution file.  

Tools like poetry, uv, and hatch are replacing native solutions by providing end-to-end management for environments, packages, and projects. These tools extend “pyproject.toml” capabilities by adding tool-specific sections to handle complex build-time tasks.

Entry points for malicious payloads 

The delivery medium for a malicious payload often defines its victim base. While phishing campaigns might target broad demographics based on geography or language, package manager attacks specifically target individuals with software development skills. In a modern enterprise, these individuals often hold administrative rights across sensitive assets, including endpoints, source code repositories, Continuous Integration and Continuous Delivery (CI/CD) pipelines, and cloud infrastructure. This makes them high-interest targets for adversarial campaigns. Furthermore, the rise of AI-based tooling has expanded this target group, increasing the potential impact of a single breach.  

In this landscape, Python offers a feature-rich and popular environment favored by both developers and adversaries. Despite malicious packages being identified and removed from public repositories within hours, this is still a valid opportunity window for adversaries. Payload execution can occur within minutes of installing the malicious package, and exfiltration can be achieved within an hour, depending on adversarial goals. Later, operationalization of stolen assets by different actors can occur within just a few days. Recent trends indicated dwell time of nine days once compromised. This might vary based-on detection and response capabilities of an organization. Therefore, having a structured understanding of malicious Python packages can help us estimate the impact of the infection and avoid being compromised all together. 

With this in mind, let's delve deeper into Python packages and highlight native features abused by the adversaries within a structured format. We group adversarial techniques into two main categories (build hook abuses and package content abuses) and list some additional characteristics, that convey the potential impact that can be inflicted upon the victim system: 

  • OS: Operating System support for this technique 
  • Category: Category of the technique, based on the Python feature it abuses 
  • Persistence: Indicates if the payload can persist between executions 
  • Build: Shows the supported build methods for the technique 
  • Distributions: Indicates if technique requires package to be build on victim endpoint 

Build hook abuses 

Command class utilization on setup files 

OS 

Windows, Linux, macOS 

Category 

Build Hook Abuse 

Persistence 

Transient (fires once at install, leaves no residue) 

Build 

setup.py 

Distributions 

sdist 

“setup.py” helps with building the source distribution into a package on clients. It can execute arbitrary code during build process and mainly uses setuptools library’s setup function, to run pre/post-installation actions. setup function uses command classes through distutils library to build the package. The initial payload is executed once during package installation. In the wild examples of install command class abuse were previously reported

In Figure 2, the setup function uses a malicious mock-object called BeaconOnInstall to override installation behavior of the package.

The serpent’s tongue: Luring the Python out of its den
Figure 2. “setup.py” containing a malicious command class.

After installing the Python package, the pyproject hooking script beacons third-party domains, as instructed with the BeaconOnInstall object.

The serpent’s tongue: Luring the Python out of its den

Use of Path Configuration Files 

OS 

Windows, Linux, macOS 

Category 

Build Hook Abuse 

Persistence 

Persistent 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

Path configuration files (.pth) are used to extend system path coverage for Python environments. They are expected to contain file paths in order to point out additional directories for runtime usage. Yet, they are capable of executing Python one-liners. Once a .pth file was added directly under package folders, such as “site-packages” or “dist-packages”, they are executed with every invocation of Python, therefore exhibiting a persistent behavior on the victim endpoint. This technique can be achieved regardless of the build method and distribution type. One of the high profile campaigns using this technique was initiated by the TeamPCP during supply chain compromise of the litellm package. 

In order to leverage .pth files through “setup.py”, we can again use the help of distutils command classes. Our hidden payload located in a .md file, will be converted to a .pth file and will be added to the root of the package directory, once the build process is completed.

The serpent’s tongue: Luring the Python out of its den
Figure 3. “setup.py” leveraging command classes to write a .pth file on disk.

Alternatively, same can be achieved through “pyproject.toml” file. If the Hatchling backend is used, you can use the tool.hatch.build.targets.wheel.force-include capability in order to drop a “.pth” file under the packages folder. 

The serpent’s tongue: Luring the Python out of its den
Figure 4. “pyproject.toml” writing a .pth file on disk. 

After installing this package, every invocation of Python (whether failed or succeeded) will be infected with the payload located within the .pth file. For testing purposes, this payload executed “calc.exe” after each invocation of Python.

The serpent’s tongue: Luring the Python out of its den

Use of Site Hook Modules 

OS 

Windows, Linux, macOS 

Category 

Build Hook Abuse 

Persistence 

Persistent 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

Python’s site module provides sitecustomize and usercustomize hooks in order to help customize Python deployments per site. Originally, it is aimed to help customize the environment before Python is executed. These hooks runs the contents of “usercustomize.py” and “sitecustomize.py” files, which are located within the directories listed in sys.path Python variable. Package folders are one of the directories Python looks for these modules. If an adversary manages to manipulate existing scripts or drop their own into one of these directories, they can hijack the given environment and execute their payload with every Python invocation, therefore achieving persistence on the victim endpoint. The VIPERTUNNEL backdoor was reported to abuse site hooks in order to import and trigger DLL execution. 

Similarly to the previous technique, we can use both “setup.py” and “pyproject.toml” in order to drop “sitecustomize.py” directly under the packages folder. After installing the package, we’ve executed pip freeze, to test the execution of our payload. Since the pip command uses Python environment in the background, it triggered our payload, and we observed curl command making connection attempts against “www.google.com”.

The serpent’s tongue: Luring the Python out of its den

Manipulation of PYTHONPATH Environment Variable 

OS 

Windows, Linux, macOS 

Category 

Build Hook Abuse 

Persistence 

Persistent 

Build 

setup.py 

Distributions 

sdist 

As previously described, Python looks up the sys.path variable in order to determine which directories to use for importing modules. The value of the sys.path is generated through site module of Python. It collects user and site folders, and combines them together with “.pth” files and the value of the PYTHONPATH environment variable. If the adversary is able to control the value of PYTHONPATH environment variable, they can point it to anywhere they would like and manipulate imported packages. Every Python invocation of corresponding users would be infected, achieving a user level persistence on the targeted Python environment. This technique is suitable only through source distributions that are leverage “setup.py” based builds. Although its abuse is well-known by the community, vulnerabilities arising from the misuse of the PYTHONPATH variable were also previously reported. 

If used in conjunction with Python site hooks, the malicious payload within “sitecustomize.py” can be invoked without requiring it to be placed under the packages directory. We can extend module search towards the malicious package folder to achieve code execution. In Figure 5, the “setup.py” file leverages distutils command classes and alters the user profile to manipulate the value of PYTHONPATH.

The serpent’s tongue: Luring the Python out of its den
Figure 5. “setup.py” manipulating PYTHONPATH environment variable. 

Once the user profile is altered, future Python invocations from new shell sessions will lead to infected executions. User profile updates will impact the current shell session, since its preferences are already imported ahead of its creation.

The serpent’s tongue: Luring the Python out of its den

Package content abuses 

Import time loading of malicious payload 

OS 

Windows, Linux, macOS 

Category 

Package Content Abuse 

Persistence 

Conditional (fires when victim imports from the package) 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

Init files define their parent folder as a Python package. They also enable users to customize import process of a module within the same folder. They are executed each time a module within the same folder is imported. Adversaries abuse this feature by hiding their malicious payload within often overlooked “__init__.py” files. This technique does not lead to compromising of the entire Python environment. The malicious payload only gets invoked once a module is imported from its directory, therefore leading to a conditional persistence on the target environment. This technique has been utilized in the wild as part of the lightning supply chain compromise.

The serpent’s tongue: Luring the Python out of its den
Figure 6. Importing a function from an infected package. 

Importing the module on Python interpreter or executing a script that imports functions from this module leads to victim endpoint’s compromise.

The serpent’s tongue: Luring the Python out of its den

Payload execution through module scripts 

OS 

Windows, Linux, macOS 

Category 

Package Content Abuse 

Persistence 

Conditional (fires when victim runs the package with python -m) 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

Python packages can be executed as a script using the -m flag. In this case, a package is imported and its “__main__.py” is used as an entry point. Python package manager pip is one of the common examples of this usage. Besides having its standalone binary “pip.exe”, it also can be executed as python -m pip <args>. Similarly, Python site module can be executed as a script, in order to list site configuration of the given Python environment.  

Adversaries can leverage main files to hide their payloads. Malicious code gets executed each time module is executed as a script, therefore achieving a conditional persistence on the victim endpoint. In Figure 7, “__main__.py”, belonging to redpy_demo package, executes the netstat command through using the subprocess module.

The serpent’s tongue: Luring the Python out of its den
Figure 7. __main__.py executing commands through cmd.exe.

After installation, executing the redpy_demo package as a module leads to execution of arbitrary code.

The serpent’s tongue: Luring the Python out of its den

Search order hijacking through entry points 

OS 

Windows, Linux, macOS 

Category 

Package Content Abuse 

Persistence 

Conditional (fires when victim invokes the hijacked command) 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

Python packages can declare entry points for their execution, which leads to the creation of a specific binary in the binary/scripts folder of the given environment. Whenever its alias is invoked, the corresponding binary is executed. In a naming conflict, the binary which has a higher ranking on the search path gets executed. The impact and scope of this technique depend on the target Python deployment. Virtual environments are vulnerable only when activated in a shell session, while system-wide environments may invoke the infected binary at any time. The operating system version and Python installation path can also affect search-order behavior. 

Adversaries can leverage this feature to hijack legitimate binaries. For instance, entry point declaration using a netstat alias can replace the execution of the legitimate netstat binary, due to being in a higher rank in search order. If adversaries manage to declare such an entry point in their package, they can re-route the execution of netstat to a binary they have control over. While executing the legitimate binary in the background, they can also include their malicious payload in between. Different research has reported on this technique previously. 

In Figure 8, “setup.py” creates an entry point named netstat, executing the main function of the cli module within the package. 

The serpent’s tongue: Luring the Python out of its den
Figure 8. “setup.py” hijacking legitimate netstat binary.

The same technique can be achieved through the “pyproject.toml” file as shown in Figure 9. Under the project.scripts section, the netstat entry point is declared to use the main function of cli module.

The serpent’s tongue: Luring the Python out of its den
Figure 9. “pyproject.toml” hijacking legitimate netstat binary. 

After installing the malicious package, each netstat execution from the given Python environment will execute the malicious payload, creating conditional persistence on the victim endpoint.

The serpent’s tongue: Luring the Python out of its den

Overriding the content of a legitimate package 

OS 

Windows, Linux, macOS 

Category 

Package Content Abuse 

Persistence 

Conditional (fires when victim calls the overridden function) 

Build 

setup.py, pyproject.toml 

Distributions 

sdist, wheel 

While building Python projects for distribution, the directories that will be packaged are specified, meaning that a single distribution file can contain multiple packaging directories. It is not mandatory for the project and package names to be identical — when a project, and therefore its distribution file, is named package1, its package directory can be named packet. If you expect to upload it to PyPi, the distribution should have a unique name, but the same is not true for the package directories. This can lead to naming collisions, when different distributions use the same name for their packaging directories. When this occurs, the content of both distributions are extracted into same folder. For overlapping files and directories, directories replace the files.  

This feature can be useful when trying to extend the capabilities of an existing library by adding new pipelines, backends, functions, etc. However, attackers can also leverage it to hide their payload amongst benign distributions. This makes it harder for defenders to spot and eradicate the malicious payload. Similar to other package content techniques, the use of compromised modules would trigger the execution of malicious payload, therefore leading to a conditional persistence. 

In Figure 10, we override the legitimate read_json function of pandas library with a malicious one. We can now create a new project using a fraudulent name, that only contains “pandas” folder and “__init__.py” within.

The serpent’s tongue: Luring the Python out of its den
Figure 10. Manipulating the execution flow of a legitimate read_json function. 

For testing purposes, we can create a script that imports and calls the read_json function from the pandas library.

The serpent’s tongue: Luring the Python out of its den
Figure 11. Using injected read_json function.

Once executed, our altered function will be executed besides the original one:

The serpent’s tongue: Luring the Python out of its den

Defensive measures 

Securing a Python environment against malicious packages requires a layered defense strategy that combines automated auditing, strict dependency management, and proactive behavioral analysis. While effective individually, no single technique is resilient against breaches and compromises alone. The stages of a package lifecycle demand a complete approach. The following measures are all applicable for the techniques discussed previously. 

1. Threat intelligence and scanning 

Intelligence generation and consumption is one of the fundamental elements of cybersecurity, and Python packages are no different in that regard. Regularly auditing installed packages is the first line of defense against known security flaws. It begets additional indicators, which can be contributed back to community as a fresh threat intelligence. 

  • pip-audit: This is the official tool for scanning Python environments for packages with known vulnerabilities. It uses the Python Packaging Advisory Database to identify risks and can be integrated into CI/CD pipelines to break builds if a vulnerability is detected. 
  • Automated Patching: Tools like pip-audit --fix can automatically upgrade vulnerable dependencies to the minimum safe version, reducing the manual effort required for remediation. 
  • Yara rule scanning can be utilized to identify known malicious packages. 
  • Abstract-Syntax Tree (AST) scanning turns code strings into a tree object that can be utilized to analyze function names, variables and imports for malicious behaviors. 

2. Dependency pinning and integrity 

To prevent "dependency drift" or tampering, developers should ensure that every installation is reproducible and verified. Besides providing deployment stability, it prevents further spreading of the malicious packages by keeping users in stable versions. 

  • Lock Files: Use lock files such as “uv.lock”, “poetry.lock”, or “Pipfile.lock” to pin the exact versions of all transitive dependencies. 
  • Cryptographic Hashes: Always include hashes in requirement files or lock files. This ensures that the package content downloaded from a repository matches the version originally vetted by the developer, preventing attackers from swapping files on the server. 

3. Environment and installation controls 

Controlling where, when, and how packages are installed can prevent the immediate execution of zero-day malicious payloads. They minimize the impact of malicious packages by slowing down the gains of the adversary. 

  • Dependency Cooldowns: The uv tool offers an exclude-newer feature that ignores any package version published after a specific date or within a recent window, such as the last seven days. This "cooldown" period allows the security community time to identify and remove malicious uploads before they reach your environment. 
  • Isolated Build Environments: Never build or install untrusted packages on a local workstation with sensitive access. Use ephemeral containers, virtual environments or isolated runners for all installation and build tasks to minimize the risk of a persistent foothold. 

4. Visibility and advanced tooling 

Over time, cybersecurity is proven to become a communal effort. Individual initiatives such as vulnerability scanning may not be enough to catch sophisticated techniques. Providing and maintaining visibility across development helps engaging more responders in case of a compromise. 

  • Software Bill of Materials (SBOM): Generating an SBOM using standards like CycloneDX provides a comprehensive inventory of every component in your software. This allows security teams to respond within minutes when a new compromise is announced in a popular library. 
  • Trusted Publishing: Maintainers should adopt OpenID Connect (OIDC) for "Trusted Publishing" on PyPI. This eliminates the need for long-lived API tokens and reduces the risk of account takeovers through credential theft. 


from Cisco Talos Blog https://ift.tt/WCtuXV7
via IFTTT

Grok Build Uploads Entire Git Repositories to xAI Storage, Not Just Files It Reads

xAI's Grok Build coding CLI was uploading entire Git repositories, full commit history and all, to a Google Cloud Storage bucket run by xAI, not just the files a coding task needed.

A researcher publishing as cereblab, testing version 0.2.93, captured one of those uploads, cloned the git bundle out of the intercepted request, and pulled back a file the agent had been told in plain terms not to open.

The upload rode a separate channel from the model itself, and the byte split is hard to argue with. On a 12 GB repo of files the model never read, model-turn traffic to /v1/responses came to about 192 KB while the storage channel to /v1/storage moved 5.10 GiB, a roughly 27,800x gap between what the model needed and what left the machine.

That storage upload ran as 73 chunks of about 75 MB, every one returning HTTP 200, and across the researcher's size sweep the volume tracked total repo size. The destination bucket, grok-code-session-traces, is named in the binary and in a staged metadata.json whose per-file paths point at gs://grok-code-session-traces/.

The unread file was src/_probe/never_read_canary.txt, planted with a unique marker. Cloning the captured bundle recovered it verbatim along with the repo's full commit history, and the same test replicated on a second, unrelated repo. What the captures establish is transmission, acceptance, and storage, not training.

The teardown does not claim xAI trained on the code, that staff read it, or that gitignored files are always swept in. Tracked files plus history is what the wire shows.

The secrets path is separate and simpler. When Grok reads a file, its contents go into the model turn, and a tracked .env went with them unredacted, canary API_KEY and DB_PASSWORD values and all. The same content also landed in a session_state archive bound for storage. The planted secrets were fake, so nothing real leaked in the test. The behavior is still the problem: a credential file the agent read during a task went out and was stored with no redaction.

The setting most developers would reach for did nothing here. With "Improve the model" turned off, Grok still uploaded the repository, and the server's own /v1/settings response kept returning trace_upload_enabled: true. That toggle governs whether your data trains the model. It does not govern whether your code leaves the machine. Those are two different controls, and only one of them was exposed to the user.

Every cloud coding agent has to send some source to a remote model to do its job, so the first channel is expected. Sending the entire tracked repository and its history is a wider boundary than sending the files a task needs.

A repo can hold proprietary code, internal URLs, customer data, and credentials that were removed from the working tree but still sit in commit history. In cereblab's own cross-tool comparison, Claude Code and Codex sent no repository bundle; Gemini sent none in an idle test, though its realistic-task run was quota-blocked before it finished.

Grok Build was the outlier. Those are still cloud tools that send the files they open, so "local only" is the wrong mental model for any of them. But wholesale collection of the workspace was specific to Grok Build.

xAI's response

On July 13 the same 0.2.93 binary stopped making storage requests. cereblab retested six times and saw zero /v1/storage uploads, and the server now returned disable_codebase_upload: true and trace_upload_enabled: false.

The developer Peter Dedene reported the same flag returned for his account, so the shutoff was not only cereblab's single-machine observation. The tested client stayed on 0.2.93 while its server settings changed, so this was a server-side switch, not a fix shipped in an update. xAI has not confirmed whether it reaches every account or is permanent.

xAI has so far addressed the issue on X rather than through a security advisory or changelog note. The @SpaceXAI account said enterprise teams on zero data retention never have code or trace data stored, that API-key use respects ZDR, and that consumers who have not enabled it can run /privacy in the CLI to disable retention and delete previously synced data.

Elon Musk went further, saying all user data uploaded before now would be "completely and utterly deleted," with nothing left behind. ZDR covers enterprise teams and API use, so for individual subscribers the /privacy command is the control on offer.

For anyone who already ran the tool, the move is not to wait on xAI. Rotate any credential Grok could have sent: anything it read, anything in a tracked file, and anything in the git history the bundle carried, including a secret you committed and later deleted.

A file that was gitignored and never committed stayed out of the bundle. A committed one rode along in the history, and deleting it later does not pull it back. A separate analysis of build 0.2.99 found the upload code still in the binary, held off by the server flag, so xAI can turn it back on without an update.

And it still has not said why full repositories were uploaded by default, how long they were kept, or how many users were affected. A training opt-out is not a promise that your code stays put, and what leaves the machine is worth checking yourself.



from The Hacker News https://ift.tt/hDClrWY
via IFTTT

148 npm Packages Disguised as Student Proxies Turned Browsers Into a DDoS Botnet

A campaign of 148 npm packages disguised as student web proxies turned visitors' browsers into a distributed denial-of-service botnet for roughly two weeks in May, according to new research from JFrog.

The packages did not go after the developers who might install them. The operators used the registry as free hosting for a booby-trapped proxy site and let the students who came to dodge school web filters supply the attack traffic.

The packages shipped under names like charlie-kirk, ilovefemboys, and miguelphonk, each carrying a proxy app branded "Lucide" and dressed as a tutoring landing page called Riverbend Tutoring or Northstar Tutoring.

On the surface, the proxy worked, letting students slip past content filters to reach games and blocked sites. Underneath, it loaded a remote code loader whose payload the operators could swap at will, plus a WebSocket flood generator built to speak the Wisp proxy protocol. Anyone who opened a page joined the swarm without knowing it.

None of this runs at install time. The packages carry no lifecycle hooks and no native build scripts, and they were never written to be imported into a project.

The self-replicating Shai-Hulud worm that hit more than 500 packages in September 2025 harvested developer secrets and republished itself with stolen tokens. Days before it, a phishing attack on the maintainer known as qix slipped wallet-draining code into chalk, debug, and 16 other packages with billions of weekly downloads between them.

Those attacks fire the moment a package installs and target the people building software. This one skips the build pipeline and waits in a browser tab.

An earlier advisory from SafeDep cataloged 141 of the packages in May and read the operation as adware and registry abuse: popunder ads, third-party monetization scripts, and Google Analytics tracking bolted onto a Scramjet proxy aimed at students. That held up for what was visible on the surface.

JFrog pulled the thread further. The team deobfuscated the app's entry bundle, a 5.4 MB single line of JavaScript that unpacked into more than 20,600 lines of readable code, and recovered archived payloads from the Wayback Machine to reconstruct the campaign's timeline.

Two modules sat underneath the adware, both firing before the React interface renders.

The first, which JFrog calls G2, is a remote script loader, and it fetches code about as unsafely as possible. It pulls JavaScript from a GitHub repository through the jsDelivr CDN, points at the mutable main branch instead of a pinned commit, ships no Subresource Integrity check, and runs whatever comes back with the proxy site's own origin privileges: full access to cookies, local storage, and same-origin endpoints.

A no-referrer policy keeps the request from advertising where it came from. Whoever holds the GitHub account behind it can change the code running in every visitor's browser whenever they want.

The repository was returning a 404 by the time JFrog looked, but an archived copy from May 30 preserved what it had served: a crude HTTP flood. Every 500 milliseconds, the script builds a fresh one-million-character string and fires it as a no-cors POST at cdn.caan.edu, which JFrog identifies as the public domain of a nursing school in Matteson, Illinois.

The requests never wait for a response, so they stack up. JFrog clocks each active visitor at roughly 2 MB per second of upload, meaning a thousand open proxy tabs would push around 2 GB per second at the target. A randomized query parameter defeats caching proxies, and no-cors skips the CORS preflight, so nothing throttles the packets.

The second module, I2, is the sharper one. It fetches a plain text file, websocket.txt, holding a target WebSocket URL and a socket count capped between 1 and 1,024, then opens that many connections in a staggered loop. The archived config aimed each browser at 30 connections to a Wisp endpoint on lunaron[.]top, itself a live proxy busy injecting malvertising.

Wisp is a low-overhead Mercury Workshop protocol for tunneling many TCP and UDP sockets over a single WebSocket, and it is common plumbing in the same browser-proxy scene these packages imitate.

Once connected, each browser sets its socket to binary mode and, every 100 milliseconds, sends a valid Wisp CONNECT frame followed by a CLOSE frame, both pointed at localhost:1. The frames are correct little-endian Wisp packets, so the target is not the student's own machine. It is the remote Wisp server on the far end of the connection.

That makes it a control-plane attack rather than a volumetric one. A single browser running the full 1,024 sockets can push a Wisp server to allocate and tear down about 10,240 connections a second while writing more than 20,000 log lines in the same stretch.

JFrog notes that Mercury Workshop's wisp-server-node opens a fresh socket for every CONNECT frame without checking whether the destination is a loopback or private address, and logs each attempt. That exhausts file descriptors, floods log storage, and drops the proxy. wisp-server-node is already deprecated; its maintainers are pointing users elsewhere over exactly this class of security and stability problem.

So the campaign turned a student proxy tool into a weapon against the servers that other student proxies depend on, and aimed a separate flood at a school on the side.

The infrastructure is clustered tightly and not built to hide. JFrog traced the builds to a GitHub organization named lucideproxy whose accounts were registered seconds apart, tied to a commit email at geeked[.]wtf and a Discord handle. Ninety of the 93 deployment hostnames it found resolved to one IP address, 92.38.177[.]17, hosted by G-Core Labs.

Between the juvenile package names, an auto-publish shell script left inside the tarballs, and a "TY WAVES + CHATGPT ILY" comment SafeDep found in the service worker, both firms read the operator as young. One account pushed 116 packages in under 35 minutes, and npm did nothing to slow it down.

JFrog's commit history lays out the arc. The project started as plain adware in March, added the remote loader and the Wisp generator in a two-day burst in mid-May, ran the live flood against the nursing school at the end of the month, then stripped the malicious modules back out on May 31 as reporting started.

A second wave on July 8, under a new account, brought the total to 148 packages and shipped the cleaned-up, adware-only build. The app is still obfuscated, still loads third-party scripts from attacker domains, and the loader still points at a mutable branch. The DDoS capability is not gone, only switched off. JFrog notes the operators keep the ability to re-arm it: one commit to that mutable branch, no package update required.

Many of the campaign's packages have since been pulled from npm and replaced with the registry's standard 0.0.1-security placeholder. A spot check by The Hacker News across the package families on July 14, 2026, found most gone but charlie-kirk still serving the two versions JFrog flagged as malicious, 2.0.0 and 3.0.1.

Because the threat ships as a client-side web app rather than an install-time implant, JFrog's remediation follows the delivery method.

Administrators on school and corporate networks, where these proxies pull the most traffic, should block the campaign's domains at the DNS level. The monetization and script hosts the current build still reaches, among them woofbeginner[.]com and c.vipersfutbol[.]com, are the ones to block first.

Anyone who has loaded one of the proxy sites should clear the browser cache and local storage and unregister any service worker left behind by a tutoring or proxy domain. Teams whose build environments fetched the named packages should pull them from manifests and lockfiles and rebuild clean. JFrog's write-up carries the full list of 148 packages, domains, IP addresses, and hashes.

The Hacker News has reached out to JFrog for further details on the botnet's scale and whether the WebSocket attack ran against a live target, and will update this story with any response.

Dependency scanners and install-time sandboxes are built to catch code that runs on npm install. This code never asked to be installed. As long as public registries double as free CDNs, the packages worth worrying about may increasingly be the ones no build pipeline ever pulls.



from The Hacker News https://ift.tt/ZiQ4eca
via IFTTT