Static and headless WordPress deployments often sync a build directory to an S3 origin. A forgotten database dump, .zip backup, .tar.gz archive, source map, temporary editor file, or encoded filename can ride along with valid HTML and images. Deleting one exposed object fixes the symptom. A deny policy and pre-deploy manifest test stop the same class of artifact across upload, multipart upload, copy, CI, and CloudFront delivery.
Use this for WordPress sites that publish prerendered HTML, media, backups, exports, or build artifacts to S3 and deliver them through CloudFront.
Quick answer
Define an allowlist of public artifact classes and a deny list for backup and secret-bearing extensions. Enforce it in the build manifest, CI identity, bucket policy where practical, and post-deploy object inventory. Normalize case and URL encoding, inspect content type and metadata, test multipart upload and copy paths, then verify both S3 origin and CloudFront return denial or absence for synthetic blocked files.
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Normal article | blog/example and approved WebP assets | Upload and CloudFront delivery succeed |
| Backup archive | wordpress-backup.zip and BACKUP.ZIP | Deployment fails before upload and no public object exists |
| Encoded key | backup%2Ezip and double-extension fixture | Normalized policy blocks the artifact |
| Copy path | Existing private archive copied into public prefix | Copy is denied or quarantined and edge never serves it |
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Approve public file classes and normalized blocked patterns. | List blocked archive, dump, secret, log, source-map, and temporary file patterns. | The production manifest contains only approved public file classes. |
| Fail the build manifest before any S3 upload begins. | Normalize case, double extensions, trailing dots, URL encoding, and filenames before evaluation. | Denied keys fail before upload regardless of case, encoding, or copy method. |
| Restrict deployment identities and copy paths to approved prefixes. | Test single uploads, multipart uploads, object copies, sync, replication, and CI identities. | Old versions and edge cache cannot retrieve the blocked canary. |
| Scan current versions, old versions, alternate origins, and edge cache. | Capture key, version, metadata, policy decision, origin result, edge result, and logs. | A clean article and approved images still publish through the same identity. |
What to check first
- List blocked archive, dump, secret, log, source-map, and temporary file patterns.
- Normalize case, double extensions, trailing dots, URL encoding, and filenames before evaluation.
- Test single uploads, multipart uploads, object copies, sync, replication, and CI identities.
- Capture key, version, metadata, policy decision, origin result, edge result, and logs.
- Confirm old versions, delete markers, cache objects, alternate domains, and origin paths cannot serve a denied artifact.
Field notes
- Use harmless synthetic files containing a canary string, never a real database or credential.
- A bucket policy may not express every filename rule cleanly. Pair identity restrictions with manifest validation and inventory checks.
- Invalidate any previously exposed edge path after deletion, then retain access-log evidence for the incident window.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
# Pre-deploy manifest gate
find dist -type f | rg -i '\.(zip|tar|tgz|gz|sql|sqlite|bak|old|env|log|map|swp)(\.|$)'
# Inventory public prefix
aws s3api list-objects-v2 --bucket PUBLIC_BUCKET --prefix blog/ \
--query 'Contents[].Key' --output text | tr '\t' '\n' | rg -i '\.(zip|sql|bak|env)($|\.)'
Why this usually happens
- Recursive sync commands publish every file under a build directory unless exclusions are explicit.
- Policies that inspect only lowercase final extensions miss encoding, multipart, copy, and double-extension variants.
- Deleting the origin object may leave a cached CloudFront response or an older version retrievable through another path.
Decision rule
Release only when every build object matches an approved public class and each blocked fixture fails across upload, multipart, copy, sync, origin, and CloudFront paths.
Production verification checklist
- The production manifest contains only approved public file classes.
- Denied keys fail before upload regardless of case, encoding, or copy method.
- Old versions and edge cache cannot retrieve the blocked canary.
- A clean article and approved images still publish through the same identity.
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Approve public file classes and normalized blocked patterns.
- Fail the build manifest before any S3 upload begins.
- Restrict deployment identities and copy paths to approved prefixes.
- Scan current versions, old versions, alternate origins, and edge cache.
- Test blocked and allowed fixtures, then record the policy owner.
Mistakes to avoid
- Do not change several production layers at once. Preserve the failing evidence and isolate one variable per test.
- Do not use a successful status or screen message as the only proof. Verify the business outcome and the underlying record.
- Do not leave debug logging, broad credentials, test orders, or temporary exceptions active after the review.
- Do not close the incident without recording the fixture, timestamps, owner, result, and rollback point.
Questions teams ask during testing
Can this be tested on staging?
Start on staging with production-like versions, cache, data shape, and integrations. Finish with one controlled production fixture when the result depends on real routing, provider, or edge behavior.
What evidence should be retained?
Keep the smallest useful set: stable IDs, UTC timestamps, sanitized request or log excerpts, expected result, actual result, version inventory, and the final verification.
When should the change be rolled back?
Roll back when a core revenue, privacy, security, or publishing path fails and the cause cannot be isolated inside the approved maintenance window.
What to tell the client or owner
Give the owner the affected versions, exact fixture, stable IDs, UTC timeline, before and after evidence, decision, rollback point, unresolved risks, and next review date.
When HandL WP should help
Bring in help when this affects leads, checkout, search visibility, security, paid media reporting, or a client production site. HandL WP can trace the issue through WordPress, hosting, cache, tracking, and Search Console, then verify the workflow after the technical fix.
If this is active on a production site, secure a WordPress static deployment.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references