
The island.is Authentication Service - In Memoriam
- 03 Feb, 2025
Want to try and exploit these vulnerabilities yourself?
Would you like to try your hand at the vulnerabilities covered in this blog post? We have developed four challenges in our developer training platform where you can try to exploit the authentication service of four fictional service providers.
Last October 2nd, the old island.is authentication service was permanently shut down, concluding an interesting and revolutionary chapter in the history of authentication in Iceland. In this blog post, we will look back on this journey and see what we can learn from it.
The Authentication Service
The Beginning
In early 2013, a new authentication service was launched by Registers Iceland. The authentication service replaced the so-called RSK web keys, which had originally been used to authenticate individuals and legal entities with Icelandic national ID numbers
It is no exaggeration to say that the arrival of the authentication service was a revolution for both public services and the private sector. It gave companies and institutions the opportunity to authenticate all Icelanders on a single platform, free of charge, thus serving the purpose of an “online identity card” as it was phrased by the Minister of Infrastructure at the time
At first, the so-called icekeys were predominantly used for authentication with the service. These were simply passwords that could be delivered to a user’s online bank or by postal mail. Before long, however, electronic IDs on mobile phones began to gain ground and enjoyed ever-increasing popularity.
The service gained immediate traction. Just over a year after the authentication service went live, 100 institutions, municipalities, organizations, and companies had implemented the service, and more than 135,000 icekeys had been issued to individuals
How Did It Work?
When applying for access to the authentication service, a service provider would specify an endpoint for receiving authentication tokens from island.is, along with its contact information, logo, and other necessary details. After the application was approved, the service provider was assigned an identifier, which was usually its domain name, e.g. ambaga.is
. To authenticate users, the service provider could then implement a link pointing to https://innskraning.island.is/?id=ambaga.is
. When this link was clicked, the user was taken to the island.is login page, which displayed the service provider’s logo.

The island.is login page
Once that login was successful, the user was sent back to the service provider’s site via a POST request to the endpoint specified in the application. There, the service provider would receive the authentication token and log the user in.

From the Registers Iceland guide: The authentication flow between a service provider and the authentication service
The Authentication Flow
The flow chart above doesn’t make this entirely clear, but one of the most important aspects of this authentication process is that the token created by the authentication service, which serves as proof of the user’s successful authentication, is sent to the service provider via the client. This means the token does not travel directly from the authentication service to the service provider. Instead, the user’s client (in most cases, a web browser) is used to relay the token.
In broad strokes, the implementation is as follows:
- A user logs in on the authentication service’s login page,
innskraning.island.is
. - Upon successful login, the user is redirected to another page, still on the
innskraning.island.is
domain.- That page contains a form with the authentication token.
- JavaScript is used to submit this form via a POST request to the service provider’s endpoint.
- The service provider receives the POST request containing the authentication token and logs the user into its system.
What is important to keep in mind in this process is that the user can not only read the token’s contents, but also has full control over it and can alter its contents before it is submitted to the service provider.
When sensitive messages such as authentication tokens are sent over untrusted channels, i.e. channels where it is possible to tamper with the messages, it is extremely important to be able to verify that the information arriving at its destination (in this case, the service provider) is correct and that its origin is certified.
This is not a new problem in computer science. One of the most common solutions, and the one used in this case, was to use public-key cryptography to digitally sign the authentication token before it was sent to the service provider.
Signatures
When it comes to digital signatures with public-key cryptography, there are two components which are most important: the private key and the public key. These keys are generated in random pairs. The private key is kept exclusively by the party that will be doing the signing (in our case, Registers Iceland)
The process of signing a message then works roughly as follows:
- The sender signs the message with their private key (the exact implementation details are not important here).
- The signature is dependent on the content of the message, so if the content changes, the signature also changes.
- The recipient of the message can use the public key to verify the signature against the message’s content.
- If the signature corresponds to the content, it proves the message has not been tampered with.
Should the contents in a signed message be changed, the signature will no longer be valid
In some cases, the public key is sent with the message in the form of a certificate. In those cases, it is extremely important to not only check if the content matches the signature, but also ensure that the certificate itself is trusted and valid.
If the origin of a signing certificate is not verified, a malicious actor can create their own certificate and use it to sign any data they wish
This is a major oversimplification of the complex system that is digital signatures, and we apologize if any details are imprecise or not technically correct. However, this explanation provides enough insight to understand the attacks we will cover below.
SAML
What do these tokens look like in practice? The method chosen for implementing the authentication service is called Security Assertion Markup Language (SAML), a widely used, XML-based authentication standard. Below is a simplified overview of a SAML token’s structure. An example of a complete, valid SAML token from the authentication service can be found here.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Issuer>Þjóðskrá Íslands</Issuer>
<Signature>
<!--
This tag contains, among other things, the signature for the message, along with the certificate that was used for the signing
-->
</Signature>
<Assertion>
<Issuer>Þjóðskrá Íslands</Issuer>
<Conditions>
<!--
Information on the authentication's validity period and what service provider is its intended recipient
-->
</Conditions>
<AttributeStatement>
<Attribute Name="UserSSN" FriendlyName="Kennitala">
<AttributeValue>1234567890</AttributeValue>
</Attribute>
<Attribute Name="Name" FriendlyName="Nafn">
<AttributeValue>Jón Jónsson</AttributeValue>
</Attribute>
<!--
Further details and metadata
-->
</AttributeStatement>
</Assertion>
</Response>
Vulnerabilities
Security vulnerabilities are a normal part of software development, as these are often highly complex systems, but their impact varies. Some vulnerabilities have almost no impact, while others can have devastating consequences. Vulnerabilities in authentication are particularly severe, as they can allow a malicious actor to impersonate any user. This would enable them to read data and perform actions in any user’s name.
Each service provider implements its own method for handling SAML tokens during authentication. With over 300 service providers, all possessing different levels of SAML expertise, using various programming languages with inconsistent support for SAML, it was to be expected that the quality and security of their implementations would vary greatly. And that was indeed the reality, some implementations proved to be secure while others contained serious security vulnerabilities.
In this section, we will review four known vulnerabilities which are known to have been found in service provider implementations of the authentication service.
Signature Not Verified (SNV)
This vulnerability occurs when a service provider, upon receiving a SAML token, fails to check if the signature matches the content. Instead, simply accepts the token’s contents as they are and uses that information to log in a user based on the data found in the XML document. To exploit this vulnerability, one only needs to generate or obtain a SAML token from the authentication service, modify the national ID number and name, and send it to the service provider’s login endpoint. In some cases, it’s even possible to remove the Signature
tag from the XML message entirely!
Impact
A malicious actor can log in to the service provider as any other user.
Signature Wrapping (SW)
Signature wrapping is a well-known vulnerability that requires special attention when working with signed XML. To understand this vulnerability, we need to dive a little deeper into how SAML tokens are signed and how those signatures are verified.
After a user logs into the authentication service, the token is constructed. This means an XML document is assembled with information about the validity period, scope, user, etc. Once that is complete, the authentication service’s private key is used to sign the entire content of the XML document.<Reference URI="">
tag)Signature
tag, which is then added to the root of the XML document. The final token is then delivered to the user to be sent to the service provider.
When the service provider receives the SAML message, it starts by verifying that the signature matches the message’s content. Remember, however, that the XML document that was originally signed did not contain the Signature
tag, as it was added after the signing process. The verification process, therefore, involves first removing the Signature
tag from the XML document and then checking if the signature matches the document without it. If the signature matches and the certificate is trusted, the token is considered valid, and we can trust all the data it contains, right? Let’s write some pseudocode where we retrieve the national ID number from the token.
# Receive the token
saml = get_token()
# Verify the token
verify_token(saml)
# Fetch the national ID number
kennitala = saml.find_all("//Attribute[@Name='UserSSN']/AttributeValue/text()")[0]
Here, we use XPath to select all Attribute
tags with the name UserSSN
and then use the retrieved value. There should only be one such tag in a valid SAML token, so it’s safe for us to just use the first (and only?) result, right?
This is a prime example of how a small, flawed assumption or a simple error in logic can have enormous consequences. It bears repeating that the origin of most vulnerabilities is a flawed assumption. Admittedly, the token is valid and the signature matches the content, but not all of the data in the token is signed. Remember that the Signature
tag is added to the token after the signing process, so its contents cannot be trusted. However, in the example above, the saml
variable contains the entire XML document, including the untrusted Signature
tag.
A malicious actor could therefore exploit the pseudocode above in the following way:
- Perform a login using the authentication service and intercept the SAML token.
- Add a new
Attribute
tag inside theSignature
tag, containing the national ID number of the individual they want to impersonate. - Send the modified token to the service provider.
The modified token would then look as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Signature>
<!-- ... -->
<Attribute Name="UserSSN" FriendlyName="Kennitala">
<AttributeValue>0987654321</AttributeValue>
</Attribute>
</Signature>
<Assertion>
<!-- ... -->
<AttributeStatement>
<Attribute Name="UserSSN" FriendlyName="Kennitala">
<AttributeValue>1234567890</AttributeValue>
</Attribute>
<Attribute Name="Name" FriendlyName="Nafn">
<AttributeValue>Jón Jónsson</AttributeValue>
</Attribute>
<!-- ... -->
</AttributeStatement>
</Assertion>
</Response>
When this token is processed by the pseudocode above, it will be considered valid because the signature matches the content, the validity period is correct, etc. However, when it comes to retrieving the national ID number, there are now two tags that meet the XPath criteria. Since the code uses the first one it finds, the data from within the Signature
tag is retrieved, data which the malicious actor has complete control over. This allows them to log in as anyone they choose.
Impact
A malicious actor can log in to the service provider as any other user.
Self-signing (SS)
As mentioned above, the SAML token contains both the signature and the certificate used to sign it. Therefore, when a SAML token is received, it is not enough to simply verify that the signature matches the content based on the included certificate; it is also essential to check if the certificate itself is trustworthy. This means verifying that it is part of a trusted certificate chain and that it has the correct issuer. If this step is missing, a malicious actor can simply create their own key pair and authentication token, sign it themselves, and include their own certificate. Anyone can create certificates and keys (e.g. using openssl
), so there is nothing to stop them from creating a certificate that has the same metadata as the real certificate from the authentication service and using it for signing. We call such messages self-signed.
A malicious actor can therefore exploit this vulnerability to sign a SAML token with any information they want, allowing them to authenticate to the service provider as any user.
Impact
A malicious actor can log in to the service provider as any other user.
Audience Not Verified (ANV)
When verifying a token, it’s not enough to only check if the signature is valid; you also need to check the token’s validity period. Last but not least, you must verify that the token is actually intended for you as the service provider. The validity period and the intended audience can be found in the Conditions
tag of the SAML token.
<Conditions NotBefore="2024-09-02T11:56:46.186368Z" NotOnOrAfter="2024-09-02T12:02:16.186368Z">
<AudienceRestriction>
<Audience>sjodir.rannis.is</Audience>
</AudienceRestriction>
</Conditions>
But why is it so important to verify the audience? Imagine a malicious actor registers a service with the authentication service, a simple game, a lottery, or something else designed to attract users. People likely wouldn’t think twice about logging into such a site using the official authentication service. However, just by logging in, the user hands the malicious actor a valid, signed token for their identity. Now, if another service, let’s say the Ambank, doesn’t verify the token’s intended audience, the malicious actor can take the token from any user who logs into their site and use it to log into the Ambank (within the validity period), impersonating that user.
Impact
This requires the malicious actor to entice users to log in to their own site, which uses the authentication service. The actor can then authenticate as any of the users who log in to their site.
Other vulnerabilities
These four vulnerabilities are by no means an exhaustive list of what can go wrong when implementing against the authentication service, but are rather the most common and serious ones we have encountered. For example, we have not discussed the consequences of failing to verify the validity period, but the impact of that vulnerability is less severe if all other checks are implemented correctly. It is also worth mentioning that the choice of using XML for the token introduces the risk of vulnerabilities such as XXE and Denial-of-service.
It should be reiterated that these vulnerabilities are not in the authentication service itself, but rather in the implementations by service providers, that is, the companies and institutions that use the authentication service.
Lessons Learned
So why are we writing a blog post about vulnerabilities in an authentication service that has already been decommissioned? Does this still matter? The new island.is authentication service is intended exclusively for public institutions and municipalities. As a result, new, privately-run authentication services have recently emerged to serve the private sector and other organizations. It is therefore vital that we look back on the journey, see what mistakes were made, and learn from them so that history does not repeat itself.
Responsibility
First, let’s talk about responsibility. If one of these vulnerabilities were to appear in my service, who would be responsible? The answer is simple: I would be. I wrote the code; I didn’t implement it correctly, so the fault is mine. What if a hundred service providers have the same vulnerability? In a legal sense, the responsibility still lies with each of them. However, at that point, you also have an indication of a systemic problem that requires further investigation.
The Guidelines
Guidelines were published in conjunction with the launch of the authentication service

From the guidelines: SAML Message Security (p. 11, translated)
The guidelines are a 26-page PDF document that covers the authentication process, the contents of the SAML messages, and various points to keep in mind when using the service. An example of a SAML token is also provided, as well as examples for how to process it in three programming languages: C# (.NET), PHP, and Java
No official libraries, packages, or modules were formally released, which meant that service providers had to write their own implementations, based on the provided examples.
The .NET Example
Let’s dive a little deeper into the .NET example. In the early days of the authentication service, a large portion of software in Iceland was written in .NET, and it is therefore likely that this specific example was used as the foundation for many implementations of the service.
First, let’s look at how the signature is verified. In this code, the certificate is found within the SAML message, and the call to CheckSignature(cert, false)
not only verifies that the signature matches the certificate, but also checks if the certificate is trusted, i.e. that it is part of a certificate chain trusted by the operating system. As a comment in the code indicates, this trust chain validation is only performed when the second parameter is false
.
The only issue was that the certificate used by the authentication service wasn’t part of any certificate chain that Windows trusted by default. Therefore, for the verification to succeed, the certificate had to be manually added to the system’s trusted certificate store. This crucial fact wasn’t clearly stated in the guidelines, which no doubt confused some developers when the example failed to work in their environment. There are cases of developers changing the second parameter to true
, seeing that everything then “worked” without realizing that this change only verified the signature itself, not the trust of the certificate. This left their implementation vulnerable to SS.
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(samlString);
SignedXml signedXml = new SignedXml(doc);
//Get and inspect the signature
XmlNodeList nodeList = doc.GetElementsByTagName("Signature");
XmlNodeList certList = doc.GetElementsByTagName("X509Certificate");
signedXml.LoadXml((XmlElement)nodeList[0]);
byte[] certData = Encoding.Default.GetBytes(certList[0].InnerText);
X509Certificate2 cert = new X509Certificate2(certData);
//It is important not to set the second value to 'true' here unless a function
//that specifically verifies the certificate's validity is implemented.
bool signatureOk = signedXml.CheckSignature(cert, false);
Next, let’s examine how the validity period is verified. There are two key things to keep in mind here: first, the doc
variable contains the entire XML document (including the signature), and second, the GetElementByTagName
function searches the entire document for tags. This code is therefore vulnerable to signature wrapping, meaning the token’s validity period can be manipulated. If a malicious actor obtains a user’s expired SAML token, they can use a signature wrapping attack to extend its validity period, allowing them to authenticate as that user indefinitely.
DateTime nowTime = DateTime.UtcNow;
//Get the time from Conditions and compare
XmlNodeList condNodeList = doc.GetElementsByTagName("Conditions");
DateTime fromTime = DateTime.Parse(condNodeList[0].Attributes["NotBefore"].Value);
DateTime toTime = DateTime.Parse(condNodeList[0].Attributes["NotOnOrAfter"].Value);
bool timeOk = false;
if (nowTime > fromTime && toTime > nowTime)
{
timeOk = true;
message += "SAML time valid. ";
}
else if (nowTime < fromTime)
message += "From time has not passed yet. ";
else if (nowTime > toTime)
message += "To time has passed. ";
The example doesn’t show how user information is retrieved, but it does demonstrate how other information from the AttributeStatement
tag is fetched, such as the IP address.
XmlNodeList attrList = doc.GetElementsByTagName("Attribute");
if (attrList.Count > 0)
{
foreach (XmlNode attrNode in attrList)
{
XmlAttributeCollection attrCol = attrNode.Attributes;
if (attrCol["Name"].Value.Equals("IPAddress"))
{
ipOk = attrNode.FirstChild.InnerText.Equals(ip);
message += "Correct client IP. ";
}
// Not in the original example, but the logic follows directly
if (attrCol["Name"].Value.Equals("UserSSN"))
{
// National ID number
attrNode.FirstChild.InnerText;
}
}
}
The most straightforward approach, then, is to retrieve the name, national ID, and other information in the same way, and that was, in fact, the case in many implementations. Such an implementation is therefore vulnerable to SW, since GetElementByTagName
is used to retrieve the Attribute
tags.
Finally, the example does not verify the message’s audience, so it is also vulnerable to ANV.
The Other Examples
The Java example is reasonably well implemented and is only vulnerable to ANV.
The PHP example, on the other hand, somehow manages to combine all of the vulnerabilities except for SNV, but we’ll let our readers have the fun of discovering them for themselves.
What was done?
At some point, it seems the flaws in the examples must have been pointed out, because by June 6th, 2019, they had been removed from the guidelines.
What can we learn?
Now that the old authentication service has been decommissioned, what can we learn from this journey?
The new island.is authentication service is intended only for public entities, but private companies and organizations can choose to use privately-run authentication services. At least eight such services are currently in operation, and more will likely be added as time goes on.
Recommendations for Authentication Services
Authentication services are a good example of the difference between securing your own software in production versus ensuring that others securely implement your APIs and libraries. It’s not enough for an authentication service provider to guarantee the security of its own systems; they must also minimize the likelihood that their clients will implement the solution in an insecure way.
It is therefore crucial for operators of authentication services to keep Murphy’s Law in mind:
If there are two or more ways to do something and one of those results in a catastrophe, then someone will do it that way.
With this in mind, we have compiled some advice that is useful for these service operators and for anyone else who builds software or web services for others to use.
- Keep documentation simple and clear.
- Clearly explain critical steps or configuration settings and explicitly state the impact of any changes to them.
- Do not provide examples in documentation with hardcoded passwords or other data that must be kept secret.
- Provide ready-made packages, libraries, modules, or fully functional code samples.
- It’s crucial that this software is secure by default.
- Implement automated security tests on service provider implementations, if possible.
- Check whether signatures are being respected and that recipients and validity periods are being validated.
- Welcome all feedback and reports.
- If vulnerabilities arise in examples or other distributed software, notify your users and ensure that everyone updates.
- Be transparent about your security matters and thus set a good example.
Lastly
Vulnerabilities are a normal, yet expensive, part of software development. The cost of a vulnerability found in a production system isn’t just measured in fines, but also in lost productivity and damage to your reputation. Ambaga places a strong emphasis on educating and training developers, because the cheapest vulnerabilities are the ones that are never created in the first place.
In our training, we place a strong emphasis on getting developers to think like a hacker and in doing so, develop the mindset needed to spot vulnerabilities. Ambaga has developed a training platform where developers get to hunt for various vulnerabilities in real-world software and learn how to exploit them. Such training reinforces for participants just how serious the impact of security vulnerabilities can be and better equips them to find them in their own software.
Finally, we’d like to remind you that if you want to try your hand at exploiting the vulnerabilities we’ve covered here, we have set up four challenges on our learning platform where the goal is to exploit the authentication service of four fictional service providers.