AWS Security Hub · ECS
ECS.5: A container has a writable root filesystem
Written and reviewed by Emnode · Last reviewed
What does AWS Security Hub ECS.5 check?
ECS.5 passes only when every container definition in a task definition sets readonlyRootFilesystem to true. It fails when the parameter is false or simply omitted, which is the default, leaving the container's root filesystem writable at runtime.
Why does ECS.5 matter?
A writable root filesystem is the first thing an attacker reaches for after landing a foothold: they can drop a reverse-shell binary, install reconnaissance tooling, or overwrite the application's own binary so malicious behaviour survives a restart. Making the filesystem read-only takes that whole post-exploitation playbook off the table: the foothold becomes ephemeral and dies with the next task recycle.
How do I fix ECS.5?
- Set readonlyRootFilesystem to true in each container definition.
- Identify paths the app genuinely writes to (temp, cache, scratch) and back them with explicit read-write volume mounts.
- Register the new revision, redeploy, and confirm the workload still starts cleanly.
Remediation script · bash
# Inventory: flag containers running as root or with a writable root filesystem.
for fam in $(aws ecs list-task-definition-families --status ACTIVE \
--query 'families[]' --output text); do
aws ecs describe-task-definition --task-definition "$fam" \
--query "taskDefinition.containerDefinitions[?user==null || user=='root' || user=='0' || readonlyRootFilesystem!=\`true\`].{Family:'$fam',Name:name,User:user,ReadOnly:readonlyRootFilesystem}" \
--output text
done
# Harden at the source. Dockerfile:
# RUN addgroup -S app && adduser -S -G app appuser
# USER appuser
# Task definition: non-root user, read-only root with one narrow tmpfs, secrets via ARN.
# "user": "1000:1000",
# "readonlyRootFilesystem": true,
# "mountPoints": [{ "sourceVolume": "scratch", "containerPath": "/tmp", "readOnly": false }],
# "secrets": [{ "name": "DB_PASSWORD",
# "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/checkout/db-AbCdEf" }]
# Register the hardened revision and roll it out (tasks only update on redeploy).
aws ecs register-task-definition --cli-input-json file://checkout-api-hardened.json
aws ecs update-service --cluster prod --service checkout-api \
--task-definition checkout-api --force-new-deployment Full walkthrough (console steps, edge cases and verification) in the lesson Harden ECS container workloads.
Is ECS.5 a false positive?
Teams assume an app that writes to /tmp can never be read-only. Mounting a writable tmpfs or volume at those specific paths satisfies the app while keeping the root filesystem read-only, so the control still passes.
More ECS controls
- ECS.2 An ECS service auto-assigns public IPs to tasks
- ECS.3 A task definition shares the host PID namespace
- ECS.4 A container runs in privileged mode
- ECS.8 Secrets are passed as plaintext container env vars
- ECS.9 A task definition has no logging configuration
- ECS.10 Fargate services should run latest platform version
- ECS.12 ECS clusters should use Container Insights
- ECS.16 An ECS task set auto-assigns public IPs
- ECS.18 ECS task defs should encrypt EFS volumes in transit
- ECS.19 Capacity providers managed termination protection
- ECS.20 Linux containers should run as non-root users
- ECS.21 Windows containers should run as non-admin users