Symptoms
- Cloud Guard problem: Bucket is public.
- Someone reports a bucket URL that opens without sign-in.
- A pre-authenticated request (PAR) link for a bucket or prefix shows up in a ticket, chat or public site.
Step 1: contain (5 minutes)
Make the bucket private:
oci os bucket update --namespace $NS --bucket-name finance-exports --public-access-type NoPublicAccess
oci os bucket get --namespace $NS --bucket-name finance-exports --query 'data."public-access-type"'
List and delete PARs:
oci os preauth-request list --namespace $NS --bucket-name finance-exports --all \
--query 'data[].{id:id, name:name, type:"access-type", object:"object-name", expires:"time-expires"}' --output table
for id in $(oci os preauth-request list --namespace $NS --bucket-name finance-exports --all --query 'data[].id' --raw-output | tr -d '[]",'); do
oci os preauth-request delete --namespace $NS --bucket-name finance-exports --par-id $id --force
done
Deleting a PAR invalidates its URL immediately.
Warning
Do not delete or overwrite the objects yet. They, their metadata and their access logs are evidence. If deletion is legally required, take a copy into a locked-down bucket first.
Stop the person or automation from re-opening it: check who made the change (step 2) and suspend that path if it is not trustworthy.
Step 2: who changed it, and when
oci audit event list --compartment-id $COMP \
--start-time 2026-10-20T00:00:00Z --end-time 2026-10-29T23:59:59Z \
--query 'data[?contains("event-type", `updatebucket`) || contains("event-type", `createpreauthenticatedrequest`)].{t:"event-time", type:"event-type", who:data.identity."principal-name", ip:data.identity."ip-address", bucket:data."resource-name"}' \
--output table
Audit retention is limited (configurable at tenancy level); export to a bucket or Logging Analytics if the incident window is long. Event type strings vary in case; widen the filter if nothing matches.
Step 3: what was read
Object reads are not in Audit. They are in Object Storage service logs (read), only if those were enabled before the incident:
oci logging log list --log-group-id $LOG_GROUP --query 'data[].{name:"display-name", type:configuration.source.category}'
In Logging search:
search "<compartment-ocid>/<log-group-ocid>/<read-log-ocid>"
| where data.bucketName = 'finance-exports' and data.requestAction = 'GET'
| summarize count() by data.clientIpAddress, data.objectName
Field names follow the service log schema; check one raw record and adjust.
| Situation | What you can say |
|---|---|
| Read logs enabled, no external GETs | Exposure without evidence of access |
| External IPs listed | Those objects were downloaded; scope notification on them |
| Read logs not enabled | You cannot prove what was accessed; assume everything public was accessible for the whole window |
Step 4: assess and report
- List what was exposed:
oci os object list --bucket-name finance-exports --all --fields name,size,timeCreated. - Classify the data (personal data, credentials, financial).
- If any credentials or keys were in the bucket, rotate them now.
- Follow your incident process for legal and privacy notification; exposure windows and data types drive the obligations.
Step 5: confirm
- Anonymous request fails:
curl -s -o /dev/null -w "%{http_code}\n" "https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/$NS/b/finance-exports/o/"
# expect 404 or 401, not 200
- No PARs remain on the bucket; Cloud Guard problem resolved.
Prevent it next time
- Security Zones on compartments holding sensitive data: they deny public buckets outright.
- IAM: only a small group gets
BUCKET_UPDATE; usewhere request.permissionconditions. - Limit PAR creation (
PAR_MANAGEpermission) and set short expiries by policy and habit. - Enable Object Storage read and write service logs on sensitive buckets now, so the next investigation has data.
- An Events plus Functions rule that reverts public buckets automatically within seconds.