Home Blog AWS Daily Intelligence #31 - The denylist had fewe…
AWS Daily Intelligence AWS

AWS Daily Intelligence #31 - The denylist had fewer spellings than the address

Verified against current vendor documentation on 12 September 2026. Pricing, limits and API behaviour were checked against the official docs on that date. Cloud services change fast — if you are reading this much later, treat the specifics as a starting point and re-check the linked sources.

Executive summary

AWS published CVE-2026-89049 on Thursday: a server-side request forgery in the Session Manager port forwarding functionality in SSM Agent, affecting every version below 3.3.4851.0 that supports remote-host port forwarding.

The mechanism is stated plainly in the bulletin. The flaw is improper validation of equivalent address representations, which lets a user bypass the remote destination denylist and reach link-local endpoints. The consequence is the one that matters: an authenticated user with port-forwarding permission could obtain the managed instance's temporary IAM role credentials and act with that role's permissions from outside the instance.

That is worth sitting with, because of what Session Manager port forwarding is for. It is the recommended way to stop running bastion hosts — no inbound ports, no long-lived SSH keys, every session gated by IAM and recorded. This turns the permission to use the safer thing into a path to the instance profile. The fix is a version number; the interim control is an IAM scope.

What changed

A denylist that was supposed to keep port-forwarding sessions away from link-local addresses could be walked around by writing the address a different way.

Item Detail
Affected SSM Agent below 3.3.4851.0 — AWS scopes it as all versions supporting remote-host port forwarding
Flaw Improper validation of equivalent address representations, bypassing the remote destination denylist
Reachable Link-local endpoints — which is where the instance metadata service lives
Impact An authenticated user with port-forwarding permission obtains the instance's temporary IAM role credentials and can use them from outside the instance
Fixed in 3.3.4851.0
Interim control Scope ssm:StartSession so untrusted principals cannot use AWS-StartPortForwardingSessionToRemoteHost

Architecture

Diagram: how CVE-2026-89049 turns a port-forwarding permission into portable credentials. A user holding ssm:StartSession opens a remote-host port forwarding session through SSM Agent. The agent holds a denylist of forbidden remote destinations intended to block link-local addresses, but the comparison is made against the literal spelling, so an equivalent representation of the same address is not matched and passes. The forwarded connection therefore terminates on the instance metadata service at the link-local address, reached from the instance's own network stack. The temporary IAM role credentials returned are ordinary credentials with no binding to the instance, so they can be used from anywhere. A second panel contrasts the IMDSv2 protections, which bind the session token to the instance, reject PUT requests carrying an X-Forwarded-For header, and default the PUT response hop limit to one — all of which target a request arriving from outside the instance through a proxy rather than one that terminates on the instance itself.
The denylist compared a spelling, not an address. Everything downstream of that comparison behaved exactly as designed.

Remote-host port forwarding exists so an operator can reach a database or an internal service through a managed instance without that instance exposing a port. The agent therefore accepts a destination from the requester, and something has to decide which destinations are acceptable.

That decision was implemented as a denylist, and a denylist of addresses has a hard problem: an IP address has many equivalent written forms. The metadata service alone is documented at 169.254.169.254 over IPv4 and at fd00:ec2::254 over IPv6 — two addresses for one endpoint before anyone starts on alternative encodings of the first. A comparison that matches text rather than resolving and normalising the address will always have gaps, and the gaps are not enumerable in advance.

This is the same failure that appeared in post #26, where a read-only mode in a database MCP server was enforced by an incomplete list of disallowed inputs in SQL validation. Different product, different language, same shape: a control expressed as a list of forbidden things, in a domain where the attacker chooses the spelling.

Business value

There is no feature here to adopt — the value is in patching quickly and in knowing what your exposure was. Two questions answer that: which principals hold ssm:StartSession without a document scope, and what the instance profiles on your managed fleet can actually do.

The second question is the one most organisations have not asked recently. This CVE converts a session permission into whatever the instance role holds, so the blast radius is not "someone reached the metadata service" — it is the union of every permission attached to every instance profile a port-forwarding user could reach.

Security considerations

The question every reader will ask is whether IMDSv2 changes the outcome. The bulletin does not address it, and the two remediations AWS gives are the version upgrade and the IAM scope. What follows is reasoning from what the IMDS documentation separately states, not an AWS statement — and it is worth being explicit about that line.

IMDSv2's protections are aimed at a request arriving from outside the instance. AWS describes it as defence in depth against open firewalls, reverse proxies, and SSRF vulnerabilities. Concretely: a PUT carrying an X-Forwarded-For header is rejected, and the response to a PUT has a hop limit of 1 by default, so a proxy one hop away cannot obtain a token.

A port-forwarding session does not arrive from outside. It terminates on the instance, and the onward connection to the link-local address is made by the instance's own network stack — which is the position IMDS exists to serve. The hop limit is satisfied, there is no forwarding header to reject, and the token is generated on the instance where it is valid.

And the piece that decides it: the documentation says the token is an instance-specific key that is not valid on other EC2 instances and will be rejected if you attempt to use it outside of the instance on which it was generated. That binding is on the token. The credentials the token lets you retrieve are ordinary temporary IAM credentials, and nothing binds those to the instance at all — which is exactly why the bulletin can say they are usable from outside the instance.

The honest summary

IMDSv2 is worth enforcing and is not the control that stops this. It hardens the path from a network position outside the instance; this attack borrows a position inside it. Patch the agent, and scope the session permission.

Cost considerations

None directly. The relevant cost is operational: upgrading SSM Agent across a fleet, which is free but not instant, and which depends on the agent being reachable — the subject of post #29.

There is an unpleasant interaction worth naming. An instance that is unmanaged cannot be updated through Systems Manager, so the machines least likely to receive this patch are the ones whose agent is already failing to check in. They are also still running the vulnerable agent.

Operational considerations

Treat this as two workstreams that run at different speeds. The IAM scope can be applied today, centrally, and does not require touching a single instance. The agent upgrade has to reach every managed node and will leave a tail.

Do the IAM scope first for that reason, not because it is the better control. Restricting ssm:StartSession so only named principals can invoke AWS-StartPortForwardingSessionToRemoteHost is AWS's stated interim measure, and it closes the path for everyone who should not have had it anyway.

Then measure the agent version distribution across the fleet rather than assuming automatic updates handled it, and reconcile that list against the unmanaged count from post #29. The two lists together are the real exposure.

Tradeoffs

Control Works well when Breaks down when
Upgrade to 3.3.4851.0 Always. It is the actual fix and everything else is mitigation. The agent cannot be reached — which is the population most likely to be stale.
Scope ssm:StartSession by document Immediately, account-wide, with no instance access required. Port forwarding is routine in how your engineers work. This removes it for whoever is scoped out.
Least-privilege instance profiles Always, and it bounds this CVE and every future variant of it. It is slow work and does not help today. It explains why the blast radius was large, not why the flaw existed.

Implementation guidance

Apply the IAM scope first. Identify which principals genuinely need remote-host port forwarding, and restrict the session permission to that document for everyone else. This is AWS's documented interim measure and it is reversible.

Then inventory agent versions and drive them past 3.3.4851.0, prioritising instances whose profiles carry the broadest permissions rather than working alphabetically. If you cannot enumerate which instance profiles those are, that is the more important finding of the day.

Finally, review CloudTrail for StartSession calls using the remote-host port forwarding document, and reconcile the destinations against what those sessions should plausibly have been reaching.

Best practices

  • Scope session permissions by document, not just by instance. ssm:StartSession without a document condition is broader than most people intend.
  • Keep instance profiles narrow. This CVE is only as damaging as the role it exposes.
  • Enforce IMDSv2 anyway — it is real defence in depth, just not against this.
  • Track agent version as a fleet metric alongside unmanaged count. Both are patch-reachability problems.
  • Be suspicious of any control described as a list of forbidden values. Prefer an allowlist, or normalise before comparing.

Who should adopt this

Everyone running SSM Agent, which is effectively everyone running EC2 at scale. The urgency scales with two things: how widely ssm:StartSession is granted, and how permissive your instance profiles are.

Organisations that moved off bastion hosts onto Session Manager — which is the recommended direction and remains so — should treat this with particular attention, because port forwarding is likely to be routine rather than exceptional in those environments.

Key takeaways

  • CVE-2026-89049: SSRF in SSM Agent remote-host port forwarding, fixed in 3.3.4851.0.
  • A denylist of remote destinations was bypassed by an equivalent representation of a link-local address, reaching the metadata service.
  • The payoff is the instance's temporary IAM role credentials, usable from outside the instance.
  • IMDSv2 binds the session token to the instance; it does not bind the credentials, which is why they travel.
  • Two speeds of response: scope ssm:StartSession today, upgrade the agent everywhere after.

Comments

How was your experience?
Your feedback helps improve this site.
PoorExcellent