The first post in this series ended on a picture of two systems. Both used RSA-2048. One was a public TLS endpoint on a customer-data API. The other was an internal key behind three layers of controls. Only one of them, the caption said, was being harvested today.
The second post ranked flows by how long their data stays valuable, and admitted it treated every Permanent-tier flow as equally exposed. The third post argued that an inventory is only useful if it records how assets connect.
This post uses those connections to answer the question every migration programme reaches sooner or later: which RSA goes first? The short answer is that an unreachable internal RSA key is a 2031 problem, and a public TLS endpoint on a customer-data API is a 2027 one. Same algorithm, same key size, four years apart. The difference is the attack path, and it can be scored.
Why the usual rankings get this wrong
Most teams sort their first quantum backlog in one of three ways.
- By algorithm and key size. Every RSA-2048 row ties with every other RSA-2048 row. A flat inventory has no way to break the tie.
- By system criticality. The core banking database rises to the top, including the internal links nobody outside the network can see.
- By severity label. "Quantum-vulnerable" is the same finding everywhere, so every row gets the same colour.
All three skip the question that harvest-now-decrypt-later actually asks: can someone record this traffic today? For signatures the question is different: can someone present a forged signature to whatever trusts it? Neither question is about the key. Both are about the path to it.
What reachability means for cryptography
For an ordinary vulnerability, reachability means an attacker can send input to the vulnerable code. For key exchange under HNDL, it means something simpler and less comfortable: an adversary can sit somewhere on the path and keep a copy of the handshake and the ciphertext. There is no exploit, and nothing touches your systems.
That flips the usual intuition. The most reachable cryptography in your estate isn't on your servers. It's on the wires between you and everyone else.
| Where the adversary has to be | Planning prior P(observe) | Typical flows |
|---|---|---|
| Anywhere on a public internet path: ISPs, transit, exchange points, cloud edges | 0.9 | Customer-facing TLS, SaaS, partner APIs over the internet |
| On the internet path between two known sites | 0.6–0.8 | Partner APIs, SFTP batches, site-to-site IPsec |
| Inside a carrier or colocation facility on a private circuit | 0.2–0.3 | MPLS, cloud private interconnects |
| Inside your network: foothold, then lateral movement, then capture | Under 0.05 | Internal mTLS, east-west service traffic |
These are planning priors, not threat intelligence. The 0.9 for internet paths is the DST report's assume-breach instruction expressed as a number: plan as if public-path traffic is already being recorded.
The internal row deserves a second look. To record east-west traffic, an attacker first needs a foothold, then needs to move to the right segment, then needs a position to capture packets. An attacker who has done all three can usually query the database directly. Harvesting the encrypted traffic for decryption a decade later is the least valuable thing they could do with that access. Internal cryptography ranks low here not because it is safe, but because quantum is not its biggest problem.
The score
We use the same attack-path model behind the 0–100 scores on our homepage:
P(A_i) = Π P(s_j | s_j−1) probability an attacker completes path i, step by step
R = Σ P(A_i) × I(A_i) summed over every path that reaches the asset
Score = 100 × (1 − e^−R) normalised to 0–100
For HNDL, each path has two kinds of step:
- Reach. The P(observe) priors above, or the product of foothold, lateral-movement and capture steps for internal traffic.
- Classical. The share of sessions on that path that still negotiate classical key exchange: 1.0 if the path doesn't support hybrid ML-KEM, and the share of legacy clients once it does.
Impact I comes straight from the shelf-life tiers in post 2, at customer scale: Permanent 3.0, Long 2.0, Medium 1.0, Short 0.1. Scale it down for small data sets.
Two properties of the formula matter in practice. Paths add up, so an asset reachable two ways scores higher than either path alone. And the exponential saturates, so a few strong paths dominate the score. That matches how attackers think: they need one path, not all of them.
Scores then map to waves and deadlines:
| Score | Wave | Baseline-track deadline | CII-track deadline |
|---|---|---|---|
| 80–100 | 1 | Dec 2027 | Dec 2027 |
| 50–79 | 2 | Dec 2028 | Dec 2028 |
| 20–49 | 3 | Dec 2030 | Dec 2029 |
| 0–19 | 4 | Dec 2031 | Dec 2029 |
Wave 1 lands ahead of the baseline track's own foundation milestone on purpose: a score above 80 means the traffic is plausibly being recorded now, and every month of delay adds to the harvest. Wave 4's 2031 date follows NIST's draft transition guidance (IR 8547), which deprecates RSA-2048 and P-256 after 2030. Those assets move on the normal refresh cycle, well inside the baseline track's December 2033 full-adoption date.
On the CII track everything is due by December 2029, so the bottom two waves collapse into one date. The score still decides what happens first inside that window. As post 1 noted, check whether any of your systems pull you onto the CII track before assuming the left-hand column applies.
Worked example: two identical rows
Back to the mid-size NBFC from post 2, on the baseline track. Its inventory contains these two rows:
| Asset | Algorithm | Key size | Location | Owner |
|---|---|---|---|---|
| loan-docs.lendco.example | RSA | 2048 | CDN + ALB, ap-south-1 | Platform |
| reporting-db mTLS (internal CA) | RSA | 2048 | Private data subnet | Data |
In a spreadsheet they tie. On the attack graph they don't.
Same algorithm, same key size, same data. The public path needs nothing but a vantage point. The internal one needs an intrusion that would already expose the data directly.
The difference in R is nearly ninetyfold. None of it comes from the cryptography.
A fix only counts on the path it closes
The platform team enables hybrid X25519MLKEM768 on the CDN. Current mainstream browsers offer it by default, so most client sessions switch to hybrid overnight. Older Android WebViews and some API clients don't, which leaves roughly one session in ten classical.
● RISK 99/100 loan-docs.lendco.example:443 (before)
client↔CDN 0.90 × 1.0 × 3.0 = 2.70
CDN↔origin 0.70 × 1.0 × 3.0 = 2.10 R = 4.80
● RISK 91/100 hybrid ML-KEM at CDN edge only
client↔CDN 0.90 × 0.1 × 3.0 = 0.27
CDN↔origin 0.70 × 1.0 × 3.0 = 2.10 R = 2.37
● RISK 24/100 hybrid on both legs (origin over hybrid TLS)
client↔CDN 0.90 × 0.1 × 3.0 = 0.27
CDN↔origin 0.70 × 0.0 × 3.0 = 0.00 R = 0.27
→ residual: legacy clients · Wave 3
The edge change is real progress for the browser leg, and it moves the score by eight points. The origin leg still carries every upload over classical key exchange across the internet. A dashboard that marks this endpoint "PQC enabled" after the CDN change is reporting a 91 as if it were a 24. Fixing the second leg, by enabling hybrid TLS to the origin or moving origin traffic onto a private connection, is what actually takes the asset out of Wave 1.
The whole estate, re-ranked
Here are the NBFC's flows from post 2, scored the same way:
| Flow | Tier | Post 2 wave (shelf life) | Reach | Score | Wave now | Deadline |
|---|---|---|---|---|---|---|
| Document-upload API | Permanent | 1 | Public, two legs | 99 | 1 | Dec 2027 |
| Loan origination to credit bureau | Permanent | 1 | Internet, partner (0.8) | 91 | 1 | Dec 2027 |
| PGP over SFTP to co-lender | Permanent | 1 | Internet, partner (0.7) | 88 | 1 | Dec 2027 |
| Branch site-to-site VPN | Long | 2 | Internet IPsec (0.6) | 70 | 2 | Dec 2028 |
| HR and payroll SaaS | Medium | 2 | Public (0.9) | 59 | 2 | Dec 2028 |
| DR replication to cloud region | Permanent | 1 | Private interconnect (0.25) | 53 | 2 | Dec 2028 |
| Marketing site | Short | 3 | Public (0.9) | 9 | 4 | Dec 2031 |
| reporting-db mTLS | Permanent | Not listed (1 on shelf life) | Internal (0.018) | 5 | 4 | Dec 2031 |
Shelf life tells you what is worth protecting. Reachability tells you what is exposed. The migration order needs both.
Two flows moved. DR replication carries the entire loan database, but it runs over a private interconnect, so it drops to Wave 2. If it ran over an internet IPsec tunnel instead (P = 0.6), it would score 83 and stay in Wave 1. The transport choice moved it, not the data. The reporting-db link would have been Wave 1 on shelf life alone, and it drops to Wave 4.
Wave 1 is now three flows. That's three conversations: one with the platform team and two with partners. It's the kind of list that actually gets finished by December 2027.
Reachability belongs to the graph, not the key
Three months later, a vendor's BI tool needs nightly extracts. Someone puts a network load balancer in front of the reporting database so the vendor can connect over the internet. It reuses the internal-CA certificate, and the extract includes PAN.
Nothing about the key changed. Same RSA-2048, same certificate, same code. One new edge appeared:
● RISK 94/100 reporting-db mTLS (internal CA) was 5/100
internal path 0.15 × 0.30 × 0.40 × 1.0 × 3.0 = 0.054
NEW: internet observer → vendor NLB → reporting-db
0.90 × 1.0 × 3.0 = 2.700 R = 2.754
→ moved from Wave 4 (Dec 2031) to Wave 1 (Dec 2027)
The score is a property of the paths around the key. Change the paths and the deadline moves, even if no one touches the cryptography.
A ranking computed once, in a spreadsheet, still says 5. That's the reason post 3 asked for an inventory that is connected and versioned over time. A reachability score has to be recomputed whenever the graph changes:
- a new listener, load balancer, NAT rule, peering link or public IP
- a security-group or firewall change that opens a segment
- a new partner integration or SaaS connection
- a new data field flowing on an existing path, which changes I rather than P
Signatures: same reachability, different clock
Post 3's jwt-signing-prod key signs tokens that a public API gateway verifies. Anyone on the internet can present a token to that gateway, so the forgery path is highly reachable. But nothing is harvested today. A forged token only works once someone can actually forge it, and a signature checked in 2026 can't be attacked retroactively.
So keep signature keys out of the HNDL ranking and give them their own track, scheduled by the lifetime of what they protect. Short-lived tokens can switch later, provided the algorithm is a configuration choice rather than a code change. Long-lived roots such as firmware signing keys, root CAs and signed documents start early, because replacing them takes years. Inside that track reachability still orders the work: a public verifier comes before an internal one.
What the score is not
- It is not a Q-Day forecast. It says nothing about when. It only says where to start.
- The priors are illustrative. Calibrate them for your estate. What matters most is the ordering they encode: internet before carrier before internal.
- A low score is not a waiver. Wave 4 assets still need to be in the inventory, with an owner and a crypto-agile design. December 2031 is still a deadline.
- "Internal" has to be earned. Cross-region links over a provider backbone you don't control, east-west traffic mirrored to a SaaS monitoring tool, and service-mesh traffic that leaves the cluster should all be scored as carrier or internet paths.
- Insiders shift the internal priors. If your threat model includes privileged insiders or provider-side access, raise the internal reach steps accordingly.
Score your own top ten
- Start from post 2's flow map. Take the Permanent- and Long-tier flows.
- List every segment each flow crosses and who could observe it. Each observable segment is a separate path.
- Check what each segment negotiates. The
openssl s_client -groups X25519MLKEM768test from post 3 sets P(classical) for anything with a reachable TLS endpoint. - Assign I from the shelf-life tier.
- Compute the score:
import math
def score(paths):
"""paths: list of (step_probabilities, impact) tuples"""
R = sum(math.prod(steps) * impact for steps, impact in paths)
return round(100 * (1 - math.exp(-R)))
upload_api = [([0.90, 1.0], 3.0), # client <-> CDN leg, classical
([0.70, 1.0], 3.0)] # CDN <-> origin leg, classical
reporting_mtls = [([0.15, 0.30, 0.40, 1.0], 3.0)] # foothold, lateral, capture
print(score(upload_api), score(reporting_mtls)) # 99 5
- Sort, band and date. Use the wave table above for your track.
- Decide what triggers a re-score, using the graph changes listed earlier, and who gets told when a Wave 4 asset jumps to Wave 1.
Most teams who do this find their Wave 1 is a handful of flows, not hundreds of keys, and that at least one of them is a partner flow that needs a conversation this quarter.
Where this series goes next
You now have a ranked, dated list. The final post covers turning it into a programme that stays finished: crypto-agility patterns that make the next algorithm change a configuration change, generating a CBOM for the FY 2027–28 procurement gate, and checking continuously that what you migrated in Wave 1 is still migrated.
Xhield scores attack paths across code, dependencies, cloud, identity and the external attack surface on the same 0–100 model, and re-scores them when the graph changes. If you've scored your own top ten flows and want to compare notes, we'd like to hear what you found: contact@xhield.tech.