← Back to blog8 in 10 Banks in Belgium HATE This One Weird eID RCE
/James Arnott
Share

8 in 10 Banks in Belgium HATE This One Weird eID RCE

TL;DR. The Connective signing extension has over 2 million users, primarily in Belgium, and lets websites talk to electronic ID (eID) and Maestro payment cards. It was used by "8 of the 10 largest banks in Belgium and 60+ Belgian government agencies and departments"1, and it underpins eIDAS qualified signatures, a signature format legally trusted by governments and organisations.

We found multiple major issues. Any site or iframe could read the user's eID and Maestro card data, and recover their eID PIN, which the binary handed back to the page inside a token that carried both the ciphertext and the key to decrypt it. Worst of all, any site could trigger a drive-by RCE by getting the native binary to load and run an attacker-supplied library. All the user sees is a file download, such as a PDF, while they are getting RCE'd.

The company behind it, Nitro Software Belgium, is a Qualified Trust Service Provider on the EU eIDAS Trusted List, the highest trust tier the regulation defines. Fixed 146 days after the first report.

What is the Connective signing system?

The Connective signing system has two parts, the extension and the native host. Web pages use the extension to talk to the native host, which then talks to the smart card readers attached to the machine to complete tasks like digital signing.

The extension is thin, acting as just a communication layer between the web pages and the native host, forwarding all messages.

It's used to authenticate with sites and to sign documents. With 2M+ users, it was stated in 2021 that Connective was used across 60+ government services and over 1,000 enterprises. We can't confirm that the Connective signing extension was explicitly used by all of these organisations, but we can confirm the 2M+ weekly active user count.

A sample Belgian eID card, front and back, marked "TEST CARD"

A sample eID

Why did we look into this?

The Connective signing extension was flagged to us after it was scanned and found to not be forwarding the origin of the request to the native host. This meant the program running on the computer didn't know which site it was speaking to, so we knew something was up.

None of the team is from Belgium, but that didn't stop us. It did present a few challenges, as we had to make a mock eID to test with.

We did see there was a token required to run all but a "version" command, which returned the version of the native host and the extension. Even with this required activationToken, we found it suspicious that the origin of the message was never forwarded to the native host, which prompted us to look further, as there was no way the native host could know the origin of the site that was messaging it.

We were actually using it as test data for our full-stack automated extension + native host scanning functionality, which is why we looked into it so much relative to our other discoveries.

Breakdown of the activationToken and token flow

The activationToken is a token cryptographically signed with RSA 2048, provided by the partnered sites that use the Connective signing extension, to give permission for a site to use the Connective system on the user's machine.

It's essentially the gateway to all of the fun commands.

This token, in its raw form, looks like this:

Lhx4xKzCIJfSRAaP2jdgdM4WYmjQ/Sremo9v/Db/8T9A+NQd6Or3NO0V3nk4Rx9OPL8oDFQfrrZETRlm1dvTt30TBaua4W0OOYuR...

Decoded via RSA signature recovery, we get this:

{
  "token": "b138fcf4-4619-47eb-846a-dc9cbeb7714d", // UUID - not used
  "ttl": 1773811513534, // 2026-03-18 05:25:13 UTC
  "features": 7 // all bits set = all ops allowed
}

This token includes a UUID, which we did not observe serving a purpose, alongside a TTL and a features bitmask. The features bitmask flags different "features" on and off:

BitEnables
bit 0GET_READERS, READ_FILE, PIN_PAD_AVAILABLE, VERIFY_PIN, COMPUTE_SIGNATURE, COMPUTE_AUTHENTICATION
bit 1unused / reserved
bit 2COMPUTE_SIGN_CHALLENGE, SELECT_MAESTRO, GET_PROCESSING_OPTIONS, READ_RECORD

The oracle we used to get these tokens was from Doccle.be, and their tokens allowed all operations and had a TTL of 24 hours.

Obviously, after decoding these activationTokens, it's clear to see they're missing the origin too. That means any web page can just replay these tokens and get full access to the Connective system on the user's machine.

Reading eIDs and Maestro cards without any permissions

So, now we have this activation token which is not tied to the origin, we can read connected eIDs and Maestro cards without the user's consent or knowledge.

The PIN token, and the attacker-controlled dialog

When we discovered how the pinToken worked, we realised this wasn't just a single mistake from a developer, we realised the developer didn't know what they were doing.

The pinToken was sent from the native host to the extension to the web page when the user entered their PIN into the native Connective dialog, so it was exposed to the web page. The structure of this pinToken interested us, as it didn't look like an ID, it looked like it had some data encoded in it, which it did.

During the Ghidra decompilation, we identified the command to request this pinToken from the user, alongside the other arguments. The message the web page had to send looks like this:

{
  "cmd": "VERIFY_PIN",
  "reader": "Pol Henarejos Pico Key HID Interface",
  "entry_title": "Belgian Government - Identity Confirmation",
  "entry_message": "Enter your eID PIN to confirm your identity for Tax-on-web",
  "activationToken": "IhOcGOSbU/w1TnQNcfz56LUkfYwzmwr4chRgyE68RHNys9jJUt4IH9dAaEVjF8..."
}

So the web page controls the text in the popup, making social engineering to get this pinToken trivial.

A native PIN entry dialog titled "Belgium National Bank Login" with attacker-controlled body text, identical to the dialog a legitimate application would show

The popup the user enters their PIN into, the exact same as it would be for a legitimate application. The title and message are attacker-controlled.

Now that any website can trivially obtain the pinToken, let's look into it. Here's a sample pinToken:

Z0WLa8YjezJpmDxkc0gzZlHcsHT/XEkZSpToKuxYVWLh+AAByPpJIGoAP3VlbtC0

From here, we can actually work out the eID PIN from this pinToken, as it contains the ciphertext and the decryption key inside of it, with a static IV. Thanks, Connective!

Step 1: Base64 decode the token, resulting in 48 raw bytes:

67 45 8b 6b c6 23 7b 32 69 98 3c 64 73 48 33 66
51 dc b0 74 ff 5c 49 19 4a 94 e8 2a ec 58 55 62
e1 f8 00 01 c8 fa 49 20 6a 00 3f 75 65 6e d0 b4

Step 2: AES-128 key (bytes 0, 2, 4, ... 30):

67 8b c6 7b 69 3c 73 33 51 b0 ff 49 4a e8 ec 55

Step 3: Ciphertext (bytes 32+):

e1 f8 00 01 c8 fa 49 20 6a 00 3f 75 65 6e d0 b4

Step 4: Hardcoded IV (found in the binary):

a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6

Step 5: Decrypted plaintext:

34 32 30 36 39 80 a7 63 98 71 01 00 00

PIN bytes: 0x34 = '4', 0x32 = '2', 0x30 = '0', 0x36 = '6', 0x39 = '9'. The rest of the bytes are a TTL for when the token should expire, which is the last 8 bytes, little-endian.

Not only does this trivially allow phishing to obtain the eID PIN, it also exposes the PIN outright, and now that we can extract the PIN, we can mint our own pinTokens to use it whenever and wherever we want. Need to forge a signature on a mortgage? What about logging into your government tax account? This has you covered, with high-trust signatures.

Once a site has your pinToken once, they can use it whenever they please, as long as your eID is connected to your computer. Even services that don't use the Connective signing extension could exploit this to use the user's eID to sign into whatever they wanted.

Expanding-brain meme escalating from "Be an employee at early stage Connective" through "let any website request the user's PIN", "let any website control the text inside the PIN dialog", "cache the PIN so the user doesn't have to re-enter it", "make the untrusted site manage the state of the cache", "expose the encrypted PIN to the untrusted site", to "expose the PIN decryption key to the untrusted site, leaking the PIN"

gigabrain moment

We were just using the Connective signing system as test data for developing our main system for analysing extensions and their native hosts en masse, we weren't expecting to find so many issues here. After we found this, we thought it best to iterate through all the available commands to see what else we could do, which is what led us to the RCE.

How this breaks the entire Belgian eID ecosystem

The Belgian eID works on one assumption: your PIN only ever goes into software you chose to run, and your keys only ever get used for something you actually wanted to do.

Everything downstream inherits that. The non-repudiation key produces eIDAS qualified signatures, which legally count the same as signing a piece of paper, which means if someone forges one, you're the one who has to prove it wasn't you.

The card never leaves the reader and the keys never leave the card, but from an attacker's point of view that hardly matters, because having the PIN plus the ability to send commands to the card is the same thing as having the card in your hand, with a wider blast radius since it works from an iframe. The user doesn't even have to visit your site. An ad or invisible tracking frame works just as well.

To take out a loan online in someone's name you need their full name, Rijksregisternummer, address, and a signature that verifies. All of that is sitting on the chip in files signed by the National Register. So you don't just get the data, you get a government-attested copy of it, plus the ability to sign whatever document you like with a qualified signature.

This isn't brilliant, but it's a one-time thing.

The itsme logo

itsme, the identity layer for Belgium

itsme is the identity layer for Belgium. It powers online banking, Tax-on-web, MyGov, MyPension, and more. If you're Belgian, itsme is probably how you log into everything that matters.

You can create an itsme account with your eID. The way that works is you sign itsme's terms and conditions with your eID on their website, using, well, the Connective plugin. That signature is the identity check. Everything after it, the token you type into the app and the SMS code, just binds that verified identity to whichever phone finishes the flow.

A sample malicious advert served inside an iframe, styled as clickbait: "8 out of 10 banks in Belgium HATE this one weird eID RCE"

Our sample malicious ad in an iframe

So what stops the phone that finishes the flow from being ours? Two things in itsme's own help pages:

  • Blocking an itsme account needs no authentication whatsoever. You go to their block page and enter the phone number and the given names exactly as written on the ID document. Phone numbers are also freely available from data brokers.
  • Once an account isn't active, itsme documents that you can activate with your eID on their website using a new number.

So what would stop us from re-enabling this with a phone we own? Not much.

The attacker doesn't walk away with a session or a signature, they walk away with a working itsme account in the victim's name, and it keeps working after the browser is closed, after the card is out of the reader, and after this extension gets patched.

We have not explicitly tested this with itsme, however we were able to demonstrate a CSAM.be account takeover which relied upon the eID for authentication. itsme also uses the affected Connective system for desktop eID verification, however there may be other steps required to create or take over an itsme account, but the main one will be the cryptographic verification with the eID.

What is most concerning here is that itsme hasn't done anything wrong. The entire eID ecosystem relies on QTSPs to be "qualified." Nitro Software Belgium is a Qualified Trust Service Provider on the EU eIDAS Trusted List, the highest trust tier the regulation defines. itsme is notified under eIDAS at Level of Assurance "High", also the top. None of this attack scenario would be the fault of itsme, it's all because of the mistakes made by Connective / Nitro.

This also raises the question, why was this allowed for so long? This extension and native host has likely had these issues for the entirety of its existence, although this is not something we can currently prove explicitly due to lack of data.

Connective stated they have yearly pen tests, so unless they were whipping out their executive ballpoint and making sure it can still scribble in SOC 2 checkboxes, we really do wonder what they were up to on these tests. None of these discoveries needed "advanced agentic LLMs", they required competent security engineers taking a look, which did not happen. We used Opus 4.[5-7] to find these issues, as we were treating the Connective signing system as test data for our platform to analyse extension native hosts.

Connective's own trust center, stating their software undergoes yearly penetration testing, as archived on the Internet Archive

Connective's own trust center, claiming yearly penetration tests from 2022

RCE via LoadLibrary

Once we fully mapped out all of the commands any web page could send to the system, we identified one interesting one, the GET_READERS command, as any page could request it like this:

{
  "cmd": "GET_READERS",
  "library": "..\\..\\..\\..\\Downloads\\lib.dll"
}

The library property in the command allows any web page to specify which DLL they want to load, and relative paths are allowed. We discovered the only limitation is that the library needs to include .dll in the file path.

Chrome automatically flags files with the .dll extension in downloads, so we couldn't just download a file with a .dll extension and run it, but we could have a polyglot named frien.dlly_reminder.pdf.

We did try to set up a remote drive to see if we could host the DLL there and provide the path, and although it would have worked, it wouldn't have worked with the standard Windows setup, so we ditched that idea.

Since we can use relative paths and the Connective signing extension is installed under AppData, we can just traverse back to the Downloads folder to execute the library.

What we could do is set up a web page that automatically downloads the frien.dlly_reminder.pdf file, so the user only needs to click a link to have this code execute at user level on their machine, escaping the Chrome sandbox.

This enabled the drive-by RCE, which we consider to be the most impactful finding from this research into the Connective signing system. There were no weird configurations required to enable this RCE, and there was nothing preventing it from potentially spreading like a worm by stealing session tokens and emailing or messaging the link to other users with the Connective signing extension for them to simply click on. There were also no security-adverse actions required from the user to enable this drive-by RCE, they simply needed to visit a website with the Connective signing extension and native host installed.

How it was fixed

Nitro rolled out the first fix on May 8th, 2026, where they added an origin check via a remote server to approve requests coming from sites before commands were executed. This did not fix the RCE or the leaking of the pinToken, it just meant only approved sites could RCE you or steal your pinToken.

Nitro had contacted us on May 19th, asking to delay public disclosure while their on-prem clients rolled out this fix. On the same day, we pointed out that the fix was not complete, the library command was still untouched (enabling the drive-by RCE) and the pinToken could still be forwarded to web pages, and we provided guidance on how this could be fixed.

The complete patch was published on June 1st by disabling the library command and caching the pinToken in the extension, giving a randomly generated UUID to the site to reference the PIN instead of the pinToken itself.

Finally, the remote origin checks were enforced from July 22nd, which blocked any site from silently reading eIDs and phishing the user's eID PIN.

Nitro's handling of this

Nitro took a long time to fix this, but they did have a security email, they did not try to coerce us into an NDA via a bug bounty program, they did actually respond (it's a very low, but real bar), and they didn't deny all the facts. If they had been quicker to act, this would have been a much better experience, but with that said, they actually did fix this in the end, which is significantly more than the other vendors we're currently dealing with.

If you are part of one of these vendors and you haven't responded, we will be roasting you more.

We also asked Nitro about a bounty. We were offered $200.

Conclusion

Throughout the initial stages of this research, we had no idea whether or not this vulnerability was real and exploitable, because we just didn't have an eID to test with, but we thought it was worth looking into.

A bingo card of the traits shared by extensions and native hosts with similar issues: legacy maintained software, native host communication, main world communication, B2B SaaS, QTSP vendor, ISO 27001, 1M+ users, used by banks, no bug bounty, "high trust" on site, and more

Bingo card of extensions and native hosts with similar issues

There are so many other extensions with similar problems, many more affecting tens to hundreds of banks, putting them at risk. Native host communication bridges to any site are dangerous, and they're not treated as such.

There also needs to be legislation to explicitly require competent pen tests on "Qualified Trust Service Providers." It genuinely feels like it's all just security theater right now, as this glaring hole in the single biggest Belgian eID signing extension on the Chrome Web Store was just missed.

Finally, thanks to the CCB for approving the publishing of this series of vulnerabilities with the legal protection from the safe harbor clause. We didn't explicitly need this, but it's nice to have.

Check out the exploit code here and check out our free scanner to see what the extensions you have installed are up to, or our organisation scanner to see what risk everyone else is putting your company at.


1 Figures as published in Connective / Nitro Software Belgium marketing. The 2M+ weekly active user count is confirmed via the Chrome Web Store and Edge listings.