Home Resume
Home Blog AWS Daily Intelligence #21 - A Path Traversal in t…
AWS Daily Intelligence AWS

AWS Daily Intelligence #21 - A Path Traversal in the SSM Agent, and Why Scoping SendCommand Was Never a Privilege Boundary

Verified against current vendor documentation on 29 August 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 two security bulletins yesterday, both path traversal. The one that matters to almost everyone is CVE-2026-81849, in the SSM Agent — the process that sits on essentially every managed EC2 instance, and runs as root.

The bulletin's own wording is the whole story: a path traversal vulnerability exists in the aws:downloadContent plugin that permits authenticated users with restricted SendCommand permissions to write files outside the intended directory with root-level access. The word doing the work is restricted. This is not a bug that gives an attacker something they were already allowed to do — it is a bug that dissolves the boundary a scoped IAM policy was drawn to create.

Affected versions run from 2.0.767.0 to 3.3.4364.0, which is most of the agent's release history rather than a recent regression. The fix is 3.3.4515.0 or later, and no workaround is offered. If your answer to "what version is the agent on our fleet" is a shrug, that is today's work.

What changed

Two bulletins, both the same vulnerability class, published the same day.

Bulletin Component Affected Fixed in
CVE-2026-81849 amazon-ssm-agent, aws:downloadContent plugin 2.0.767.0 to 3.3.4364.0 3.3.4515.0
CVE-2026-81838 awsdac (diagram-as-code) 0.10 through 0.23 0.24

The awsdac issue is a Zip Slip: a crafted archive can write files outside the intended cache directory, to any path writable by the user running awsdac. It is the smaller of the two — a developer tool, run interactively, usually not as root — and the mitigation while you upgrade is to process definition files only from sources you trust.

The SSM Agent issue is the one with fleet-wide reach, and the rest of this post is about that.

Architecture

To see why this matters more than a typical agent CVE, it helps to be precise about what a Run Command permission actually is.

Diagram: a caller whose IAM policy allows only one SSM document sends a command; the SSM Agent, running as root, resolves the destination path in the aws:downloadContent plugin; a traversed path writes a file outside the intended directory onto a root-owned path, leading to code execution. Three cards below give the affected versions, the fixed version with no workaround, and the two-week auto-update check interval.
The IAM policy bounded which document could run. It never bounded which file the agent would write.

What the plugin is for

The aws:downloadContent plugin downloads SSM documents and scripts from remote locations, and Systems Manager supports the following source types for downloading scripts and SSM documents: GitHub, Git, HTTP, S3, and SSMDocument. It is ordinary, useful plumbing — the step that fetches a script before another step runs it — and it appears inside AWS-owned documents as well as custom ones.

It takes a destination on the instance. The agent resolves that destination and writes there. The agent runs as root on Linux and as SYSTEM on Windows, because that is what a management agent has to be to install packages and edit system configuration.

Why "scoped SendCommand" is a weaker control than it reads as

The standard way to delegate Run Command safely is to grant ssm:SendCommand with the Resource element naming specific document ARNs and specific instance ARNs, often narrowed further by tag. A reviewer looking at that policy concludes: this principal can run these documents on those instances, and nothing else.

That conclusion has always contained an assumption, and it is the assumption this CVE broke. The policy bounds which document executes. The document's behaviour is then bounded by the plugins it invokes — and those plugins are code running as root, taking parameters from the request. Document scoping narrows intent. It does not narrow blast radius, because there is no mechanism underneath it that constrains what the agent's plugins may touch on disk.

Read that way, every ssm:SendCommand grant is a conditional grant of root on the target instance, where the condition is the correctness of the plugin implementation. That is not a criticism of the design; it is the nature of a management agent, and it is true of every configuration management tool ever shipped. It is worth saying plainly because the IAM policy is so legible that it invites a stronger reading than it can support.

Business value

There is no feature here and no value to capture — only exposure to remove. The business framing that matters is the second-order one: this bulletin is a free test of whether you can answer two questions about your fleet.

  • What version of the SSM Agent is running, per instance, right now? If the answer takes more than a query, agent patching is not a controlled process.
  • Who holds ssm:SendCommand, and against which instances? That list is your practical root-access list, and it is usually longer than the list of people anyone would describe as having root.

Organisations that can answer both in ten minutes will close this out today. Organisations that cannot have just learned something more valuable than the patch.

Security considerations

The severity comes from the composition, not from the primitive. Path traversal on its own is a familiar bug. Path traversal in a process running as root, reachable by a caller whose permissions were deliberately narrowed, is a privilege escalation with an audit trail that looks completely normal — the CloudTrail record is a SendCommand the principal was authorised to make.

AWS states the outcome directly: this could enable arbitrary code execution if sensitive system files are overwritten. Overwriting is the mechanism — a writable path plus root ownership reaches things like scheduled jobs, service unit files and authorised key files without needing an exploit of any other component.

Two implications worth acting on beyond the upgrade:

  • Treat the SendCommand grant list as a privileged-access list. Review it on the same cadence as your break-glass roles, not on the cadence of ordinary application permissions.
  • Do not rely on document scoping as an isolation boundary between tenants or environments. Use separate accounts, or at minimum separate instance profiles and tag-scoped instance ARNs, so that a plugin defect does not cross an environment line.

Cost considerations

Upgrading the agent is free. Systems Manager charges nothing for Run Command or for State Manager associations in the standard tier, so an account-wide auto-update association adds no line item.

The cost that is real is operational: an agent restart during the upgrade briefly interrupts in-flight sessions and command executions. On a fleet running long Session Manager sessions or long-running commands, the sensible pattern is a maintenance window rather than an immediate fleet-wide push — and the trade against leaving a root-level path traversal in place for another week is not a close one.

Operational considerations

This is where most fleets will discover a gap, and it is the reason this post is worth more than "patch it".

Automatic agent updates are a setting you turn on, not a default. When you do turn it on, the documented behaviour is that Systems Manager automatically checks every two weeks for a new version of the agent, and if there is a new version, Systems Manager automatically updates the agent to the latest released version using the SSM document AWS-UpdateSSMAgent.

Two weeks is a perfectly reasonable interval for keeping an agent current. It is not a patch response. "Auto-update is on" answers the question are we drifting; it does not answer are we fixed today, and conflating the two is how a fourteen-day exposure gets recorded as remediated in a ticket.

Three platform exceptions to check before you assume a single mechanism covers the fleet:

  • Bottlerocket. SSM Agent on the Bottlerocket operating system can't be updated using the Systems Manager Command document AWS-UpdateSSMAgent; updates are managed within the control container. Any EKS estate on Bottlerocket needs a separate answer.
  • macOS. If an instance is running macOS version 11.0 (Big Sur) or later, the instance must have the SSM Agent version 3.1.941.0 or higher to run the AWS-UpdateSSMAgent document — so the oldest machines, which are the ones you most want to update, are the ones the update document cannot reach.
  • Immutable images. Updating running instances does not update the AMI. If the pipeline rebuilds hosts from an image that carries an affected agent, the fleet re-acquires the vulnerability at the next scale-out.

Tradeoffs

Approach Speed to patched Risk Use when
Immediate fleet-wide AWS-UpdateSSMAgent via Run Command Minutes Agent restart interrupts in-flight sessions and commands The exposure outweighs the interruption, which for a root-level traversal is most fleets
State Manager association, rate expression Next scheduled run Stays correct afterwards; slow for this specific event You want the durable control as well — pair it with a one-off push now
Maintenance window Next window Predictable, but the window may be days away Workloads genuinely cannot tolerate an unscheduled agent restart
Rebuild from a refreshed AMI Next deployment Slowest, but the only one that fixes the source Always, in addition to one of the above — not instead of it

Implementation guidance

Find the affected instances first. SSM Inventory records the agent version, so the fleet-wide answer is one query rather than a survey.

Which managed instances are below the fixed version
aws ssm describe-instance-information \
  --query "InstanceInformationList[?AgentVersion!='3.3.4515.0'].\
[InstanceId,PlatformType,PlatformName,AgentVersion,PingStatus]" \
  --output table

That lists everything not on the fixed build, including instances already ahead of it, so read the versions rather than trusting the filter. Then push the update to the ones that need it:

Update the agent across the fleet
aws ssm send-command \
  --document-name "AWS-UpdateSSMAgent" \
  --targets "Key=InstanceIds,Values=i-0123456789abcdef0" \
  --comment "CVE-2026-81849 - agent to 3.3.4515.0 or later"

Target by tag rather than by instance id for anything above a handful of hosts, and stagger it with --max-concurrency if the fleet is large enough that a simultaneous agent restart is itself an event.

Then make it durable. Turn on Auto update SSM Agent on the Settings tab in Fleet Manager if it is off — accepting that it is the drift control, not the incident response — and add the agent version to whatever inventory dashboard your team actually looks at.

For awsdac, upgrade to 0.24. Until then, process definition files only from sources you trust.

Best practices

  • Know the agent version the way you know the OS patch level. The agent is privileged software on every instance and is routinely absent from the patch reporting that covers the OS.
  • Enumerate ssm:SendCommand holders and review them as privileged access. The grant is legible enough to look narrow and powerful enough to be root.
  • Scope Run Command by document and by instance, always. Scoping does not survive a plugin defect, but it bounds which fleet a defect reaches, which is the difference between an incident and an outage.
  • Fix the AMI as well as the fleet. An instance-level patch that the next scale-out undoes is a temporary fix recorded as a permanent one.
  • Subscribe to AWS security bulletins. Both of yesterday's items were published there and nowhere a developer would have noticed them.

Who should adopt this

Everyone running the SSM Agent, which in practice means everyone running EC2 — the agent is preinstalled on the current Amazon Linux and Windows Server AMIs, so "we never installed it" is usually wrong.

Two groups should treat it as urgent rather than routine. Teams that delegate Run Command to a wide set of engineers or to automation, because the vulnerability's premise is a caller who already holds a scoped grant. And teams running multi-tenant or mixed-sensitivity workloads on shared instance fleets, where the document-scoping assumption is doing isolation work it cannot do.

Teams running Bottlerocket or macOS fleets should confirm their update path before assuming coverage, for the reasons above.

Key takeaways

  • Upgrade amazon-ssm-agent to 3.3.4515.0 or later. Affected versions span 2.0.767.0 to 3.3.4364.0, and no workaround is offered.
  • The vulnerability's premise is a restricted caller. It converts a deliberately narrowed ssm:SendCommand grant into root-level file writes, which is why scoping alone did not contain it.
  • Auto-update checks every two weeks. That is drift control, not incident response; push the update explicitly.
  • Bottlerocket and older macOS instances need a different path, and an unpatched AMI reintroduces the issue at the next scale-out.
  • The same day brought CVE-2026-81838, a Zip Slip in awsdac 0.10 through 0.23, fixed in 0.24 — smaller reach, same class of defect.

Comments

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