Imagine you’re auditing a corporate environment. The client has Netskope deployed on all endpoints, blocking policies configured, DLP up and running, and the console showing millions of events per day. On paper, all traffic leaving each device passes through the platform before reaching the Internet and blocks anything that isn’t legitimate or that contains sensitive data. It’s one of those claims the client takes for granted, and that we, as pentesters, should verify.

The uncomfortable question is: what if it isn’t true? What if there are entire processes whose traffic never appears in SkopeIT, isn’t inspected, isn’t filtered, and doesn’t generate a single log entry? Not because of an agent bug or a product vulnerability, but because of a legitimate Netskope feature that’s been misconfigured, something any user on the device, without administrative privileges, can discover and exploit with a couple of commands.

In this article, I’ll walk through how to identify this type of vulnerable configuration during a pentesting engagement: where to look, what to find, how to document it for the report, and what to recommend to the client. The technique revolves around a specific component of the agent, Certificate Pinned Apps, and, above all, around what happens when that feature is deployed without the proper precautions.


What Is Netskope?

The simplest way to explain what Netskope is: it’s a cloud proxy. An intermediary through which all traffic leaving corporate devices passes before reaching the Internet.

The idea is the same as a traditional proxy (those servers companies had, and still have, in their offices so that employee traffic would pass through them before going out to the web and restrictions could be applied). What changes with Netskope is where that intermediary lives: instead of being physically located in the office, it’s distributed across a global network of cloud points of presence. This allows the model to work just as well for someone sitting at corporate headquarters as for someone working from home.

To ensure all traffic passes through it, Netskope installs an agent on each corporate device. That agent runs silently in the background at the kernel level and has a simple mission: grab all network traffic generated by the device and redirect it to the Netskope cloud before it goes out to the Internet. Once there, the platform reviews it, applies the policies the company has defined, and decides what to let through and what to block.

The most important piece to understand is that Netskope can only make decisions about the traffic it sees. If a process on the device manages to send traffic to the Internet without going through the Netskope cloud, that traffic becomes invisible to the platform: it isn’t inspected, it isn’t filtered, and, most importantly for a security team, it never appears in the console.

That’s the foundation for everything that follows. When we talk later about bypassing Netskope, we’re not referring to fooling the inspection engine or evading a specific policy: we’re referring to making a process’s traffic leave the device without the platform ever even knowing about it.

Steering Exceptions and Certificate Pinned Applications

All of this works in an ideal environment, but the reality is different. In practice, this doesn’t always work. There are applications that simply refuse to operate if their traffic passes through an intermediary.

The reason is called certificate pinning. Some applications have the certificate of the server they expect to communicate with hardcoded inside the software itself. When they connect, they’re not satisfied with the certificate simply being trusted. They compare it against the one they have embedded, and if it doesn’t match exactly, they drop the connection. It’s a legitimate security measure, designed to prevent anyone from inserting themselves between the application and its real server, not even an apparently valid certificate.

The problem is that Netskope, being a proxy, does exactly that: when it inspects encrypted traffic, it presents its own certificate to the client instead of the original. For most applications this isn’t an issue, because the Netskope certificate is installed as a trusted authority on the corporate device. But for applications that perform certificate pinning, it doesn’t work. They don’t want a trusted certificate; they want their certificate. If they receive a different one, they fail. And the list of applications that behave this way is not short: Microsoft Teams, Zoom, Dropbox, etc.

Netskope needed to coexist with these applications without breaking them. The solution is called Steering Exceptions: exceptions to the mechanism that redirects traffic to the cloud. When an application is marked as an exception, the agent doesn’t capture its traffic and it goes directly from the device to the Internet through the operating system’s normal route.

An important nuance is that for Certificate Pinned Apps defined in Netskope, Tunnel Mode can be implemented, which causes traffic to exit through the Netskope cloud (avoiding the need to open destinations in the perimeter firewall) but without any inspection.

These exceptions are a necessary feature, not a flaw. Without them, deploying Netskope in a company that uses Teams or Zoom would be an operational nightmare. The problem isn’t that they exist, but how they are configured. And this is where the opportunity for the pentester arises.

Reconnaissance Phase: Extracting the Configuration

As a pentester, the first thing you need to know is what exceptions the client has configured. Without that information you’re working blind; you might suspect something is misconfigured, but without access to the console you can’t know for sure. The good news is that all of this information lives on the user’s own device, and retrieving it requires no administrative privileges and no vulnerability to exploit.

The Netskope agent stores the complete list of Steering Exceptions for the tenant in a local file called nsbypass.json, typically located (though this can vary) at:

C:\ProgramData\netskope\stagent\nsbypass.json

This file is, in essence, a local copy of the exception configuration that the tenant administrator has defined in the Netskope console. Every time the agent starts or receives a configuration update, it syncs this file with what’s in the cloud and uses it as a reference to decide, in real time, which processes on the device should be excluded from steering and under what conditions.

Its contents are a structured JSON that includes both the Certificate Pinned Apps Netskope ships by default and the custom exceptions the administrator has added for their environment. For each entry, it specifies the application name, the process it applies to, the affected domains, and the mode in which traffic should leave the device. In other words: all the information you need to understand which processes are outside of Netskope’s reach in that tenant.

Obviously, both Netskope and many administrators of the tool are aware of how sensitive these configuration files are, and apply Anti-Tampering protections to prevent modification or deletion of components, as well as in many cases their reading.

The problem is that the Netskope agent includes a utility called nsdiag that serves a specific purpose within the product’s support lifecycle. When a user has issues with the agent, the typical flow is for the support team to ask them to generate a diagnostic bundle so they can review what configuration is applied to the device and which domains it has connected to.

nsdiag -o generates a zip containing everything support needs to reconstruct the state of an endpoint’s agent, including the applied configuration files, among them the one we’re looking for, nsbypass.json. That is, by design, the tool delivers the complete Steering Exceptions configuration of the tenant to any user, without requiring administrative privileges.

"C:\Program Files (x86)\Netskope\STAgent\nsdiag.exe" -o nslogs.zip

Logs can also be retrieved if you have access to the graphical interface via the Netskope icon → Save Logs

Analysis Phase: Vulnerable Certificate Pinned Apps

With the nsbypass.json file in hand, the next step is knowing what to look for inside it. The file typically has dozens of entries, mixing the predefined Certificate Pinned Apps that Netskope ships out of the box with the ones the tenant administrator has added for their environment. Most are reasonable: well-known applications with pinning, narrowly scoped domains, and consistent operating modes. The work we need to do is identify the ones that aren’t reasonable.

{
    "action": 1,
    "appName": "[Teams]",
    "app_domains": ["*"],
    "isRegex": "false",
    "mode": "direct",
    "processName": "ms-teams.exe",
    "rowID": "custom_28",
    "tunnel_domains": []
}

At first glance this looks like a normal entry, an exception for Microsoft Teams associated with the ms-teams.exe process. But there are three very interesting fields:

  • app_domains - Defines which domains the exception applies to. The original intent is for a Certificate Pinned App to cover only the application’s traffic to the servers that application actually needs. If the entry has a “*”, it means every domain passing through this process will go directly to the Internet without going through Netskope.
  • mode - This field tells us whether the traffic falls under direct, meaning it goes from the endpoint to the Internet without passing through Netskope (useful in environments without a perimeter firewall), or tunnel, meaning it will travel through the Netskope tunnel but without any inspection or policy evaluation, leaving only minimal traces in the logs (the better option in environments with a perimeter firewall)
  • processName - We need to know the name of the operating system process that is authorized to benefit from the exception.

So, how does the agent decide that a process is ms-teams.exe? The short answer is that it decides solely based on the name of the executable. It doesn’t check the binary’s digital signature, it doesn’t validate a known hash, it doesn’t verify the path from which it’s running or the file’s publisher; if a process is named ms-teams.exe, the agent treats it as Teams for the purposes of the Certificate Pinned App.

An unprivileged user can copy any binary to a path where they have write permissions, rename it to ms-teams.exe, and execute it. The agent will see a process called ms-teams.exe, apply the exception to it, and let its traffic go outside the platform’s reach.

Exploitation Phase - Proof of Concept

From our analysis of nsbypass.json, we’ve concluded that entry custom_28 matches the vulnerable pattern: app_domains: "*" with process ms-teams.exe. On paper, this should allow any binary renamed to ms-teams.exe to send traffic outside of Netskope’s reach, to any destination, without any restrictions.

For the agent to treat the process as Teams, we need an executable named ms-teams.exe that can browse or make requests to external URLs. The quickest approach is to rename the device’s own chrome.exe, although it’s worth noting that any client with an active EDR will detect this renaming and block it as Process Hijacking.

copy "C:\Program Files\Google\Chrome\Application\chrome.exe" "C:\temp\ms-teams.exe"

To avoid precisely this detection (this is EDR bypass territory, unrelated to Netskope and unnecessary if no active EDR is present), the alternative is to bring in an external binary not originally on the device. In this test, wget in its portable version for Windows was used, downloaded from one of the project’s usual public builds. Once placed in a path where the user has write permissions, it just needs to be renamed to match the process name defined in the vulnerable Certificate Pinned App.

Copy-Item "C:\temp\wget.exe" "C:\temp\ms-teams.exe"

The resulting binary is functionally identical to wget, but the Netskope agent, which identifies processes solely by processName, will treat it as if it were Microsoft Teams.

To demonstrate the bypass conclusively, the test is performed in the same console with the same binary in both versions: first with its original name, and then renamed as ms-teams.exe. The chosen URL is http://directoalpaladar.com, which belongs to the Food & Drinks category, blocked by an active policy for the purposes of this test.

Netskope bypass proof of concept: blocked request with wget (403 Forbidden) versus successful request with the binary renamed to ms-teams.exe (301 Moved Permanently)

With the unmodified binary, Netskope intercepts the request and returns a 403 Forbidden. The traffic has passed through the cloud, the policy has been evaluated, and the blocked category has done its job: the connection is dropped before reaching the real server. Next, against the same URL, from the same device, but running the renamed binary, we see the server respond with an HTTP 301 Moved Permanently redirecting to the HTTPS version, the binary follows the redirect, and finally saves the wget output to an HTML file. The policy simply wasn’t applied, because the traffic never reached the cloud.

Obviously, we’re talking about a simple proof of concept: accessing a blocked but legitimate website. However, if we think further, we can see new attack vectors that this misconfiguration enables.

The Vendor’s Response to This Finding

After documenting the finding, it was reported to Netskope through the vendor’s standard disclosure channel. It is a misconfiguration, but one that could be enumerated without any restrictions. The vendor’s response can be summarized as: this is the expected behavior of the product.

The vendor’s argument rests on three valid points that place responsibility with the administrators or the client, not the product.

The first is that Certificate Pinned Apps must exist to solve a real problem that cannot be ignored, and that any mechanism allowing traffic to be exempted from steering will, by definition, have a surface for misuse. It’s not a design flaw; it’s a misconfiguration.

The second is that the described pattern is not Netskope’s recommended configuration. The tool’s best practices state that explicit domain lists should be used in app_domains to verify that the traffic matches what is expected for the application.

The third, and to me the most controversial, is that Netskope explicitly recommends not disclosing these definitions to the general user base. That is, the vendor assumes that the tenant’s exception list is information that should be kept out of reach of end users. The problem is that, as we’ve seen, this information travels in nsbypass.json and is delivered, bundled, to any user who saves logs on the machine.

This combination is what defines our attack surface in a pentest. The product is designed to support secure configurations, but it also allows configurations that open a complete bypass. And the information needed to identify those configurations is accessible to any user on the device.

At its core, it’s not very different from what happens in an Active Directory environment. Active Directory is not a vulnerable product, but practically every domain compromise follows a similar pattern: permissions delegated to users or groups that shouldn’t have them, ACLs configured too broadly, etc. The product supports both secure and insecure configurations, and the attacker finds their opening in the gap between the two. With Netskope it’s exactly the same: the pentester’s responsibility isn’t to prove the product is broken, but to find the client’s configuration decisions that left the door open.


If you’ve made it this far, thanks for reading. And remember: the next time you audit an environment protected by Netskope, spend five minutes on the nsbypass.json. A single entry with app_domains: ["*"] could be one of the best findings in the report.