Any of over 12000 RIPE Atlas probe hosts could have hijacked a RIPE NCC user’s login. A single link click planted a session token in their browser. When the user next logged in to a RIPE NCC service, possibly much later, the attacker could access their account. An XSS variant did the same regardless of the victim’s session state.
The RIPE NCC single sign-on (SSO) cookie crowd.token_key was not
rotated on login. After fixation, the attacker would have full read and write
access to every RIPE NCC service: the RPKI dashboard, the RIPE Database,
the member portal. An attacker could also silently add new API keys
or new admin users1.
After my XSS+CSRF exploit chain on RIPE NCC RPKI and Database
and the following SSO cookie exposure to 1000 third parties,
I thought I might have reached the limits of what I could find. But I
had a feeling that, even though the CAA record on probes.atlas.ripe.net
now blocked TLS certificates for my p1013767.probes.atlas.ripe.net
probe at home, there might still be a vulnerability. Last month I found one.
I reported this in April 2026, and it was fixed within three weeks. But the structural pattern that makes attacks like this possible, hosting third-party infrastructure under the same domain as the all-powerful SSO cookie, has not changed.
What is session fixation
Session fixation is session stealing, inverted. When stealing, the attacker takes a valid session that already exists. In fixation, the attacker plants a token they already know in the victim’s browser, then waits for the victim to log in. After login, the same token is now an authenticated session, and the attacker can use it.
The standard mitigation is to rotate the session token on authentication: the unauthenticated browser gets one token, then a fresh one after login. RIPE NCC’s SSO setup did not do this. Tokens issued before authentication were promoted to authenticated tokens in place, rather than replaced.
Two further details made this practical:
- Pre-authentication tokens are served on the initial page
load of
access.ripe.net. Anyone visiting the login page without an account gets one. - The session token is not bound to IP, device, or browser.
So: grab an unauthenticated token, plant it in a victim’s browser, wait for them to log in, use the token. I found two ways to plant a token.
Variant A: XSS in RIPEstat through NS records
RIPEstat rendered DNS NS records without sufficient escaping. An NS record
whose name contains an XSS payload would have caused the payload to execute
in the context of stat.ripe.net.
A live example was reachable at
https://stat.ripe.net/resource/c.d.s42.re#tab=dns while the bug was open,
because the zone d.s42.re has this NS record:
d.s42.re. 300 IN NS ns.<marquee><h1/onmouseover=alert(1)>marquee<img/src='//s42.re/d.png'/crossorigin='anonymous'>.d.s42.re.

The SSO cookie is HttpOnly, so a javascript payload cannot directly
overwrite it. The existing cookie can be evicted using cookie jar
overflow2 though, clearing the way for the attacker’s planted cookie.
This works here because the XSS runs in HTTPS context, so javascript can
set new secure cookies, which forces the legitimate secure cookie out of
the per-domain cookie limit. RIPEstat had no Content-Security-Policy,
so an import() to fetch a dynamically generated payload would have
worked.
Variant A required an XSS in *.ripe.net. Once that was the case, the
planting worked regardless of the victim’s session state. This XSS has
been patched.
Fun fact: that RIPEstat URL still showed the marquee tag in one of the widgets. RIPE NCC initially chose to cleanse the HTML rather than escape it3, which was the wrong choice in this context, riskier, and I recommend against it. Some time later, they applied proper escaping.
Variant B: planting the cookie from an Atlas probe

The harder, but more fun variant, is to plant it from a RIPE Atlas probe. Ideally a software probe, as installing your own web server is trivial. Having a free RIPE NCC account and filling out a form is enough.
RIPE NCC assigns each probe a hostname under *.ripe.net. The probe runs on
the operator’s network, on their IP addresses. A CAA record on probes.atlas.ripe.net
prevents me from requesting a TLS certificate, so I can’t run HTTPS.
The Secure flag on RIPE NCC’s SSO cookie
prevents the browser from sending it without HTTPS. But none of this
stops us from planting our own cookie.
Executing the attack
- The attacker visited
access.ripe.netwithout logging in. The page issued a freshcrowd.token_key. The attacker kept it. - The attacker ran an HTTP server on their probe that returned a page
setting
crowd.token_key=<the captured value>; domain=ripe.netvia aSet-Cookieheader. - The attacker sent the victim a link to the probe on
pxxx.probes.atlas.ripe.net. - The victim opened the link. The token was planted in their browser. The page could show some innocuous content to not raise suspicion, or something to entice the user to log in on a RIPE NCC platform.
- At some later point, the victim logged in to any RIPE NCC service. The same token was promoted to an authenticated session. The attacker had about 8 hours to use the access4 unless the user explicitly logged out.
- The attacker could then use the token to access the session. That included adding a new account as an admin user, or adding an API key. The victim was not notified of these changes1.
The probe link looks slightly more suspicious than some of my previous
work, but the hostname is genuinely under ripe.net.
I think enough people will still open it.
The full setup on my side, end to end:
- Register to host a software probe. Approval was automatic.
- Install Atlas probe software on a Linux machine. RIPE NCC pointed
p1013767.probes.atlas.ripe.netat my IP a short time later. - Install nginx.
- Serve an HTML page that plants the cookie.
The minimal payload:
<marquee>welcome to my website</marquee>
<script>
document.cookie = "crowd.token_key=ATTACKERVALUE; domain=ripe.net; path=/";
</script>
This sets a non-HttpOnly cookie, which is fine for fixation: the server only checks the value.
My more refined version used a small CGI script. Compared to the minimal
payload, it fetched a fresh unauthenticated token from access.ripe.net
per request (so each victim got a distinct one), planted it via a
Set-Cookie header, and logged the source IP and session token
for later use:
#!/usr/bin/python3
import urllib.request, http.cookiejar, os
jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
opener.open("https://access.ripe.net/")
token = next(c.value for c in jar if c.name == "crowd.token_key")
with open('/var/www/html/log.txt', 'a') as f:
f.write(f"{token} {os.environ['REMOTE_ADDR']}\n")
print(f"""Content-type:text/html
set-cookie: crowd.token_key={token}; Domain=ripe.net; Path=/; HttpOnly; SameSite=Lax; Max-Age=34560000
<h1><marquee>welcome to my website</marquee></h1>
""")
This is the exact script I used for this demo:
In the video, the left browser is a simulated attacker, the right a simulated victim. The bottom panel tests connectivity from a network that the attacker marks “do not route” in the RPKI Dashboard.
There is one important constraint. The planted cookie is non-secure
(served over HTTP), so it cannot directly overwrite an existing Secure
cookie5. If the victim has an active legitimate crowd.token_key, my
planted one is rejected by the browser. The legitimate cookie is a
session cookie in the strict sense, expiring when the browser closes (in
principle), so catching the victim with no existing cookie is plausible.
Unlike the legitimate cookie, my planted one isn’t a session cookie, so it persists in the browser. If the victim logs in during this persistence window, the planted token becomes their authenticated session, and the attacker can access it. The window stays open as long as the SSO backend recognises the value: at least 24 hours by my measurement. Once the backend expires the row, the cookie still sits in the browser but is worthless.
Cookie jar overflow as used with the XSS attack does not work for this scenario. Secure and non-secure cookies overflow separately. Filling the non-secure pool from HTTP context cannot evict the existing Secure cookie.
Why probes again
This is not the first time *.ripe.net hosts run by strangers became a
security problem. The
SSO cookie exposure post covered
the same architectural choice from a different angle: cookies leaking
to third-party hosts. This time, third-party hosts are planting cookies in
visitors’ browsers.
The fix from the previous case, restrictive CAA records on mtg.ripe.net
and anchors.atlas.ripe.net, does not help here at all. CAA controls who
can issue TLS certificates. This attack uses plain HTTP. CAA is not
involved.
Impact
A successful fixation gives the attacker complete authenticated access to the victim’s RIPE NCC account. This is the same outcome as the leak through insufficient CAA records, reached through a different route.
This includes full read and write access to the RPKI dashboard, the RIPE Database, the member portal, RIPE Atlas, billing data, support tickets, and any API keys or personal data visible there. Persistence via API key creation or admin user addition also applies here.
Most of these actions don’t currently notify the user, although for admin users it depends on the method1. RIPE Database changes are an exception: most users have notifications configured on their objects, which the attacker cannot disable.
What was fixed
RIPE NCC fixed both vulnerabilities within three weeks of the report:
- The XSS in RIPEstat was patched.
- The session fixation in
access.ripe.netwas fixed by adding the missing token rotation.
RIPE NCC said a strict Content-Security-Policy on RIPEstat is in progress.
IP-binding of session tokens was considered by RIPE NCC, but not adopted for usability reasons.
Beyond the immediate fix
Beyond fixing the session fixation and the XSS, I made the same structural recommendations as after the previous post:
- Do not put third-party infrastructure under the SSO cookie’s domain scope.
- Add additional authentication requirements for critical actions.
- Notify the user when critical actions are taken.
Atlas probes still run under *.ripe.net. The architectural pattern
that puts strangers’ infrastructure inside the SSO cookie’s trust scope
persists. Right now this is no longer exploitable, because
session fixation is fixed and the previous CAA gaps are closed.
But it remains a precarious configuration.
RIPE NCC has indicated they are aware of the risks and are working
towards a structural solution.
Disclosure
This report went much smoother than the 14-month disclosure I documented earlier. The total time from report to fix was 20 days. I received a bug bounty of € 1100.
RIPE NCC still responded more slowly than their committed timeframes, Intigriti triage was difficult to pass, and the bounty required pushback from me.
Nonetheless, I applaud the much improved handling of this report.
Full timeline:
| Date | Event |
|---|---|
| 2026-04-02 | I report to Intigriti: XSS in stat.ripe.net and session fixation in access.ripe.net. After triage requests details, I send a proof of concept and demo video the same day. |
| 2026-04-06 | Intigriti triage requests a full post-exploitation scenario. |
| 2026-04-08 | I provide a second video showing RPKI ROA changes from a hijacked session. Intigriti triage downgrades severity from Exceptional to High (€ 700), citing S:U (scope unchanged) and A:N (no availability impact). I push back. |
| 2026-04-17 | RIPE NCC reaches out, indicates investigation is underway. |
| 2026-04-22 | RIPE NCC confirms both XSS and session fixation are fixed. |
| 2026-04-29 | Report accepted at High. I re-raise the severity question. |
| 2026-05-01 | RIPE NCC agrees on S:C, severity raised to Critical. |
Reflecting on my own work
After finding this, I audited IRRD, the IRR software I maintain. I found IRRD was theoretically vulnerable to the same class of session fixation: the session token was not rotated on login. There were no known exploitation paths, but I have fixed this in IRRD 4.5.2.
Other posts on RIPE NCC
- Taking down a European network with a TLS certificate: my RIPE NCC RPKI exploit chain
- 1000 third parties could have stolen RIPE NCC session tokens - by design
- Inside a 14-month responsible disclosure with the RIPE NCC
This post was shared with RIPE NCC for factual review prior to publication. Factual feedback from RIPE NCC has been incorporated.
I'm Sasha Romijn, an independent developer and internet infrastructure specialist in Amsterdam. I find security issues in internet infrastructure, usually in configurations, trust relationships, and cross-system behaviour that got overlooked. Previous finds include rooting OpenWrt via SSID and, some years back, compromising Apple keychain access groups.
Find me on Mastodon, Bluesky, or work with me.
To be precise, adding a user with an existing RIPE NCC Access account triggers a notification to current admins. Adding a new user by email that does not yet have an Access account sends no notification to admins, only an invitation to the new user. This is presumably an oversight. RIPE NCC has also indicated that notifications for API key additions are planned. ↩︎ ↩︎ ↩︎
Cookie jar overflow is documented at HackTricks, based on the per-domain cookie limits in RFC 6265 §5.3. ↩︎
The OWASP Cross-Site Scripting Prevention Cheat Sheet recommends output encoding (escaping) over sanitization for general XSS prevention. Sanitization is reserved for cases where rendered HTML is actually expected, which is not the case for an NS record name. ↩︎
Measured: the SSO backend accepted a planted pre-authentication token for at least 24 hours after issue, three times the post-login session’s 8-hour lifetime. After login, the authenticated session was usable for about 8 hours; periodic refresh did not extend this, and explicit logout rotates the cookie and ends the window. Not measured: the upper bound on the pre-authentication planting window. Browser cookie caps (400 days in Chromium) are the absolute ceiling. ↩︎
The rule that a non-Secure cookie cannot overwrite an existing Secure cookie is normative in RFC 6265bis §5.7. ↩︎