✓ Human-authored analysis; AI used for formatting and proofreading.
We use presigned URLs to share reports with providers. Are we HIPAA compliant? The discussion is split between "they're temporary, it's fine" and "they're a ticking time bomb." The nuance is in what your bucket policy enforces.
The Problem
A presigned URL embeds IAM credentials into the URL itself. Anyone with the URL can download the object without AWS credentials or MFA check. Default expiration is up to 7 days for IAM user credentials. If a presigned URL to a PHI object leaks via email, Slack, or a log file, you have an uncontrolled access window to protected health information.
The bucket policy doesn't restrict presigned URLs by default. Presigned URLs bypass IAM policies, VPC endpoint conditions, and IP restrictions. Unless the bucket policy explicitly includes conditions for s3:signatureAge or s3:authType.
The HIPAA Citation
HIPAA section 164.312(a)(1) requires access controls that restrict access to electronic PHI to authorized persons. A presigned URL that can be forwarded to any person on the internet is not an access control. It's an access delegation with no audit trail of who used it.
How Stave Detects It
Stave control CTL.S3.PRESIGNED.001 checks whether the bucket policy includes presigned URL restrictions:
id: CTL.S3.PRESIGNED.001
name: Presigned URL Access Must Be Restricted
severity: medium
compliance:
hipaa: "164.312(a)(1)"
unsafe_predicate:
all:
- field: properties.storage.kind
op: eq
value: bucket
- field: properties.storage.access.presigned_url_restricted
op: eq
value: false
The control checks for two specific guardrails in the bucket policy:
-
s3:signatureAgeLimits how long a presigned URL remains valid. ADenystatement withNumericGreaterThanons3:signatureAgeof 600000 (10 minutes) forces short-lived URLs. -
s3:authTypeADenystatement withStringNotEqualsons3:authTypeset toREST-HEADERblocks presigned URL access, requiring direct IAM authentication.
stave evaluate \
--controls controls/s3/access/ \
--observations observations/ \
--eval-time 2026-04-08T00:00:00Z
Security State: NON_COMPLIANT
Findings:
phi-reports-bucket:
CTL.S3.PRESIGNED.001 UNSAFE Presigned URL access unrestricted
Bucket policy does not restrict presigned URL access. Presigned
URLs can provide long-lived unauthenticated access to objects.
Remediation: Add a Deny statement with Condition NumericGreaterThan
s3:signatureAge (e.g., 600000 for 10 minutes) or StringNotEquals
s3:authType REST-HEADER to block presigned URL access.
Presigned URLs are inherently uncontrolled. The security comes from the bucket policy conditions that constrain them, not from the URLs themselves. If your PHI bucket policy doesn't include s3:signatureAge or s3:authType conditions, every presigned URL is a potential breach vector with no expiration guardrail beyond the IAM credential lifetime. Stave flags this gap before an auditor or an attacker finds it.
Top comments (0)