Skip to main content
Article · What we test

A scanner finds nothing in a thick client and that is not a result

A web scanner starts from an address and works outwards through whatever each response hands it. A desktop application hands it an installer. There is no address to start from, no markup to parse, no request it can read and nowhere addressable to put a payload — so the run completes, the report is empty, and the empty report gets filed. This is what is on the other side of that blank page.

Yash K · · What we test · about 12 min

The empty report

The scan came back clean, and it was never going to come back otherwise

This is not a tuning problem, a licence problem or a question of pointing the tool somewhere better. It is structural, and it is worth being precise about why.

A web scanner does the same two things. It fetches something, and it reads what came back for places to go next and places to put a payload. Anchors, forms, script, redirects, parameters, headers, path segments — each one is a named, addressable location, and the whole discipline of automated web testing rests on the fact that a response tells you where the application continues. A thick client tells you nothing, because a thick client is a compiled program that talks to a server, and the conversation it has is not made of documents. There is no first address. There is no markup describing what the application can do, because the operations are code paths rather than links. There is no response body in a format anything but the client itself can decode. Point a scanner at a desktop application and it has not failed — it has correctly reported that it found no surface, which is true, and which is not the same statement as the one the report gets read as. The surface exists. It comes into being when the program runs, it is made of whatever the two ends agreed to speak, and somebody has to construct a way of seeing it before a single test can be attempted.

The six prerequisites

What a crawler needs before it starts, and what a desktop application offers instead

Read down the first column. Each row is something a web application supplies for free and a thick client does not supply at all.

What the tool needsWhere a web application supplies itWhat a thick client supplies
Somewhere to begin The address you typed into the tool. Everything else in the run is reached from it. An installer. Nothing in the package is obliged to announce which servers it will reach, and a program that has not been run yet has not reached any of them.
Somewhere to go next Anchors, forms and script, parsed out of each response and added to a queue that drives the whole crawl. A compiled interface. The operations it can invoke exist as code, and code does not enumerate itself to anybody standing outside the process.
A request it can read and rewrite A method, a path, headers and a body, in a format a proxy parses without being told how. Whatever the two ends settled on: a length-prefixed binary frame, a serialised object graph, a long-lived socket carrying something that is not HTTP in any respect.
A session it can hold A login form it can fill, and a cookie or header it can replay on every request afterwards. An authentication exchange inside the protocol, with the credential assembled by code whose behaviour is written down nowhere outside the binary.
A response it can judge Text to match against for an error, a stack trace, a timing difference, a payload coming back reflected. Bytes the client alone knows how to decode. To the tool it is a length and a blob.
Somewhere to put the payload A parameter, a header or a path segment — every one of them named and addressable. A field inside a structure whose layout is defined by agreement between client and server and recorded in neither of them.

Somewhere to begin

Where a web application supplies it
The address you typed into the tool. Everything else in the run is reached from it.
What a thick client supplies
An installer. Nothing in the package is obliged to announce which servers it will reach, and a program that has not been run yet has not reached any of them.

Somewhere to go next

Where a web application supplies it
Anchors, forms and script, parsed out of each response and added to a queue that drives the whole crawl.
What a thick client supplies
A compiled interface. The operations it can invoke exist as code, and code does not enumerate itself to anybody standing outside the process.

A request it can read and rewrite

Where a web application supplies it
A method, a path, headers and a body, in a format a proxy parses without being told how.
What a thick client supplies
Whatever the two ends settled on: a length-prefixed binary frame, a serialised object graph, a long-lived socket carrying something that is not HTTP in any respect.

A session it can hold

Where a web application supplies it
A login form it can fill, and a cookie or header it can replay on every request afterwards.
What a thick client supplies
An authentication exchange inside the protocol, with the credential assembled by code whose behaviour is written down nowhere outside the binary.

A response it can judge

Where a web application supplies it
Text to match against for an error, a stack trace, a timing difference, a payload coming back reflected.
What a thick client supplies
Bytes the client alone knows how to decode. To the tool it is a length and a blob.

Somewhere to put the payload

Where a web application supplies it
A parameter, a header or a path segment — every one of them named and addressable.
What a thick client supplies
A field inside a structure whose layout is defined by agreement between client and server and recorded in neither of them.

Three constructions

There is no surface until somebody makes one

Each of these produces something a scanner would need in order to start. None of the three can be produced by scanning.

01 The wire

Getting between the client and the server

What is there to begin with
A connection, and the knowledge that bytes are moving along it. Nothing that can tell you what any of those bytes mean, or which of them correspond to an action a user took.
What has to be done
The transport has to be terminated somewhere under your control, and the frames crossing it have to be parsed into operations, one at a time, before a single one can be altered and sent back.
What it yields
The first artefact in the whole exercise that resembles a list of requests — and it was manufactured rather than discovered, which is the entire difference from a web assessment.
02 The package

Reading what the application was told to trust

What is there to begin with
A file your users double-click, carrying everything the program needs to reach a server it will never be told about at runtime.
What has to be done
The package is opened and read for the decisions that were compiled in rather than configured: where it connects, what it presents in order to get in, and which of the checks it performs are the only copy of that check anywhere.
What it yields
Destinations, credential material and trust decisions — none of which a crawler could have requested, because there was no responder to request them from.
03 The machine

Reading what the run leaves behind

What is there to begin with
An installed program and a session used the way a real one gets used, on a computer whose disk and registry are part of the application whether anyone scoped them or not.
What has to be done
Local state has to be captured while the program is live, because what is not captured then can be overwritten or removed by the time the process exits and cannot be recovered afterwards.
What it yields
Artefacts with a path and a list of accounts that can read them. There is no worse version of this that a scanner performs — a scanner has no concept of a local file, so it does not attempt it at all.

The protocol

Pointing the tool at the port does not rescue it

It is the obvious next move, and it is worth following through to where it stops, because it stops early.

Suppose you skip the client entirely and aim the scanner at the port the client talks to. The tool connects and begins doing the one thing it knows: sending requests shaped like HTTP requests and reading replies shaped like HTTP replies. The server on the other end is speaking something else. It either closes the connection, or answers with a framing error, or waits for a handshake that never arrives — and the run ends with the same empty report by a different route. Even where the transport happens to be HTTP underneath, the payload riding on it is a serialised structure that the scanner has no schema for, so it cannot locate a field, cannot substitute a value, and cannot recognise that the reply it got back was an authorisation failure rather than a success. Its entire attack corpus is written in a language of parameters and it is looking at a language of messages. Add certificate pinning compiled into the binary and even the observation problem gets harder: the client will refuse to speak through anything it was not built to trust, which has to be dealt with in the program before the protocol becomes visible at all. None of this is exotic engineering. It is simply work that happens before scanning, which is why a product whose whole design assumes the surface already exists reports that there is nothing there.

Weakness classes

Five weaknesses that live where a crawler has never been

The first two carry a measured rank and it is an archive-wide rank: across the whole engagement archive, every coverage class pooled together. It is not a thick-client frequency, and no figure on this page is attached to the desktop class.

Five weaknesses that live where a crawler has never been
StateWhat it meansWhat follows
CWE-798 · Use of hard-coded credentials A username, password or token compiled into the program because the program had to authenticate to something and there was nowhere else to put it. It ships to every machine the installer reaches, identical on all of them. A crawler sees none of it. The string sits in a file on a disk it never had.
CWE-321 · Use of a hard-coded cryptographic key The key that protects the traffic, the licence check or the local store, shipped inside the artefact it protects. Recovering it is not an attack on the cryptography; it is reading the package. A crawler sees none of it, and would not know a key if a response handed it one.
CWE-319 · Cleartext transmission of sensitive information A protocol nobody watched, because watching it needed a parser somebody had to write. Not being HTTP keeps the traffic out of the sightline of the tools that look at traffic. Visible only once the frames on the wire have been turned into operations.
CWE-306 · Missing authentication for a critical function A server operation the interface draws for nobody, reachable by anything that can construct the message. The interface is the access control, and the interface is running on hardware somebody else owns. Unreachable by a tool that can only send messages the official client would send.
CWE-284 · Improper access control Terminal The account can ask for it, and the server answers. Whether it should have is a decision that was taken in the client, at a point where it could only ever have been advice. Requires two accounts, a message from one and an answer meant for the other.
Key
  • Second and third most frequent across the engagement archive — every coverage class pooled, not a desktop figure
  • Recorded across the same archive. No rank and no count is stated for it
  • TerminalNo state follows this one

Sourcing

Where those two rankings come from, and what they do not say

The archive-wide CWE ranking, stated beside the claim that uses it As of 2026-09-15
  • The ranking is taken across the whole engagement archive — every coverage class Security Brigade has worked, pooled into a single set and counted by weakness identifier.
  • Hard-coded credentials (CWE-798) and hard-coded cryptographic keys (CWE-321) sit second and third in that set by frequency.
  • Cleartext transmission (CWE-319), missing authentication for a critical function (CWE-306) and improper access control (CWE-284) are recorded in the same archive. No rank is stated for them, and none is implied by the order they appear in above.
  • Every engagement Security Brigade has run since the firm started in 2006 was worked inside Lemon, which is where that archive lives and what trained the models the platform runs on.

Deliberately excluded

  • It is not a thick-client frequency. The ranking was taken across every class at once, so no count and no proportion anywhere on this page is attached to the desktop class.
  • It is not a prediction about your application. A weakness being frequent across an archive says nothing whatever about whether it is in the binary you distribute.
  • Physical, hardware and wireless testing, which are out of scope for the platform in every class.

The paper trail

Four ways an empty result gets written down

Each of these is a sentence somebody wrote in good faith. Each one reads, a year later, as a statement about the application.

Filed as

‘No vulnerabilities found’

The tool ran, reached nothing, and produced a report with the target named across the top of it. Nobody reading that report afterwards can distinguish an application that was tested and found sound from one that was never reachable in the first place.

Filed as

‘Not applicable’

The honest version. The tool declined the target because it could not parse it, and somebody recorded that accurately. The exception is correct on the day it is written, and it becomes permanent, because nothing was scheduled to take its place.

Filed as

‘Covered by the server test’

The interface behind the client was assessed, driven by a request corpus captured while the official client was used. That corpus is, by construction, the set of messages the developers meant to exist — which is the one set that proves least about what the server will accept.

Filed as

‘Out of scope’

The desktop client was never in the application inventory, because an application inventory is a list of addresses and this application has no address. The same blindness, one layer further up, deciding what gets tested at all.

Send the installer your users get, and see what actually reaches it

One scan is one application or one target, and the entry price is $500. A paid trial is $299. Thick client is one of the five application classes the self-serve flow reaches.