Lock attachments in Confluence Cloud with Sentinel Vault, step by step
Mihai Perdum
Author
13 min readOctober 4, 2026
Key takeaways
END STATE: one attachment on a Confluence Cloud page sealed with Sentinel Vault, an overwrite by a second account reverted automatically, both versions visible in the attachment history and over the REST API, and the seal released again.
Confluence Cloud can't lock an attachment on its own. CONFCLOUD-2841 has asked for it since 2005 and has 163 votes.
A seal doesn't block the upload. It puts the sealed version back as a new version, 2.6 to 4.6 seconds later on our production install, and the rejected upload stays in the history.
Anyone who can edit the page can seal a file, except on a page Approved in a Sentinel Vault workflow. The seal holds for the space default (48 hours unless a space changes it) or 1 day to 1 year.
Known bug in 6.6.0: if the person who sealed the file uploads a new version, the seal still points at the old one. Release and seal again after your own upload.
Confluence Cloud has no built-in way to lock attachments. The request for one, CONFCLOUD-2841 "Provide locking for attachments", has been open since 2005 and carries 163 votes. Sentinel Vault, the Confluence app we make, gets you the closest working thing: you seal the file, and when somebody uploads over it, the sealed version is back on top a few seconds later. On our production install that took between 2.6 and 4.6 seconds, over three runs on 2 October.
It isn't a lock in the check-out sense. I'd rather you know that before Step 1. A Forge app can't stop Confluence from saving an upload. So Sentinel Vault lets the save happen, downloads the sealed version and uploads it again as a new version. The rejected upload stays in the version history. That's useful when someone's change was right after all. We wrote up why it has to work this way in you can't block a Confluence save, so I won't repeat it here.
By the end you'll have one file sealed on a real page, a second account's overwrite reverted, both versions visible in the attachment history and over the REST API, and the seal released again. One more thing up front, because it changes how you use it. Running this, we hit a bug in our own app: if you sealed the file and then upload a new version yourself, the seal keeps pointing at the old one. The workaround is in the "If it didn't work" section below.
We ran the walkthrough below on 2 October 2026 on our demo site, which runs the production build, 6.6.0, signed in as me with Gabriela's account as the second user. The two checks that ran on our test site instead say so where they appear. Afterwards the page was deleted and purged.
Note
Prerequisites
A Confluence Cloud site and a site admin who can install apps. Sentinel Vault is on the Atlassian Marketplace. Atlassian bills it, and on 2 October the listing's pricing data priced the 10-user tier at 0. This tutorial was written against 6.6.0, released 2 October.
Edit permission on the page that holds the file. That's all sealing needs.
A second account that can also edit the page, to play the person who overwrites the file.
For Steps 3 and 5 on the command line: an Atlassian API token for each account, plus curl, jq and shasum. We ran them with curl 8.7.1 and jq 1.7.1 on macOS.
1
Install Sentinel Vault
a site admin, once, from the Marketplace listing.
2
Seal the attachment
page ⋯, Apps, Seal attachments…, tick the file, Seal 1 attachment.
3
Overwrite it as another user
same file name, same page, second account.
4
Read the attachment version history
the rejected upload and the app's revert, side by side.
5
List the versions over the REST API
and hash them to prove the sealed bytes came back.
6
Release the seal
Release on the file's row, and uploads stand again.
A seal remembers one version and puts it back
One picture before the clicks. It's short. When you seal a file, Sentinel Vault records which version it is (v1 here). From then on, every new upload to that file triggers a check, and who uploaded it decides what happens.
Who uploads
What happens
Anyone without access
Reverted: the sealed version comes back as a new version
Someone you gave edit access
Kept, and it becomes the new sealed version
You, the person who sealed it
Kept, but the seal still points at the old version (the bug)
Anyone, after the seal expires
Kept. An expired seal stops enforcing straight away
5 rows × 2 columnsHeader row enabled
One exception: on a page that is Approved in a Sentinel Vault workflow, only its approvers and space admins can seal or change a file, so even you and your grantees get reverted there.
The seal follows the attachment's id, not its name. Remember that. It matters later.
Step 1: Install Sentinel Vault from the Atlassian Marketplace
A site admin installs it once, from the listing, and accepts the permissions it asks for.
There's no switch to flip after that. I like it that way. Sealing isn't behind a site setting, and anyone who can edit a page can seal its files (Approved pages are the exception, see above). The defaults that matter here: a seal lasts 48 hours unless a space sets its own default, and the app tells an editor when their change is undone. Signed seal actions (a 6-digit authenticator code) are off by default. Leave them off for this test. I'd turn them on later, once people know what a seal is.
To check it worked, open any page. Under the title, next to the author, you'll see a small Sentinel Vault item in the byline. That's the app's door on every page. No item, no install.
Step 2: Seal (lock) an attachment on a Confluence Cloud page
Attach the file you want to protect to a page. Our test used a 93-byte price-list.csv on a page called "Supplier price list Q4 (sealed file demo)".
Open the page's ⋯ menu at the top right, choose Apps, then Seal attachments…. Our own README says "choose Seal attachments…" and skips the Apps step. On current Confluence Cloud it sits one level down, under Apps. You'll need it. (Yes, our README is wrong there. It's on the list.)
The door is one level down: ⋯, Apps, Seal attachments…. Production install (6.6.0) on our demo site, 2 October 2026.
The dialog lists every file on the page with a checkbox. Tick the one you want. Then set two fields:
Seal holds for. The first option is the space default (it read "Space default (1 day)" on our demo space). The rest of the list runs from 1 day to 1 year.
Note (optional). Why it's sealed, up to 300 characters. People see it with the seal.
I'd pick the shortest duration that covers the job. A seal that outlives its reason just trains people to ask for edit access.
Click Seal 1 attachment. If your site has signed seal actions switched on, you'll get a Sign this action box first. Type the current code from your authenticator and click Sign and continue. If you've never set one up, the app sends you to its My work page to scan a QR code. That takes a minute. On a default site you won't see any of it.
You should see a green 1 attachment sealed. bar. The file's row now carries a SEALED · YOURS label and the expiry.
After sealing: the row names the sealed version (v1), the expiry, and offers Release. The fields you just used sit underneath.
The byline item under the title changes to Sealed (1). Good. Now go and break it.
Step 3: Overwrite the sealed file as another user
Sign in as the second account and upload a file with the same name to the same page. In the browser, that's dragging the file onto the page or uploading it from the attachments list. Confluence treats a matching name as a new version of the same attachment.
We did it from the command line, so the timestamps would be exact. A PUT on the page's attachments creates or updates by filename:
bash
1exportSITE=https://your-site.atlassian.net
2exportPAGE_ID=31129606# the page id from the page's URL3exportSECOND_TOKEN=... # the second account's API token45curl-s-u"second.user@example.com:$SECOND_TOKEN"-X PUT \6"$SITE/wiki/rest/api/content/$PAGE_ID/child/attachment"\7-H'X-Atlassian-Token: no-check'\8-F'file=@price-list.csv'-F'comment=Updated A-100 price'\9| jq -r'.results[0] | "\(.id) \(.title) v\(.version.number) \(.version.by.displayName) \(.version.when) \(.version.message)"'
Confluence accepted it as v2. That part is meant to happen. Don't panic. Wait five seconds, then reload the page as yourself.
As the owner, you should see a banner at the top: "A change to your sealed attachment price-list.csv was reverted automatically."
What the owner sees on the next visit: an Undone banner naming the file, and Sealed (1) in the byline.
The person who uploaded gets told too. On a default site they get a page comment headed "Your change was undone", which says the file is sealed and how to ask for edit access. We didn't see that exact comment, because our demo site has the app's comment switches on. There, a fuller "Seal Violation" comment went out, naming both of us. Either way, each reverted upload gets its own comment. Three stubborn uploads, three comments.
Step 4: Read the attachment version history in Confluence
Confluence's attachment version control is where you can see what happened. Open the page's attachments list. The quickest way is this URL, with your page id:
Expand the file. Each overwrite leaves two rows: the upload that was rejected, and above it a version by Sentinel Vault with the comment "(Sentinel Vault automatically reversed modifications)".
Two reverts in one history. Versions 3 and 6 are the app. Version 6 put back version 1's bytes, not my own version 4. That's the bug explained under If it didn't work, below. Times shown in UTC+3.
Ours has six versions because we kept going after the first revert, and that's how the bug showed up. You should see three: your original, the other account's upload, and the app's revert. The rejected upload stays there. If it turns out to be the right file, nobody lost it.
Step 5: List attachment versions with the Confluence REST API
The history page is fine for one file. It doesn't scale. For an audit, or to prove the revert really restored the same bytes, use the REST API. First, the attachment id:
bash
1exportTOKEN=... # your own API token23curl-s-u"you@example.com:$TOKEN""$SITE/wiki/api/v2/pages/$PAGE_ID/attachments"\4| jq -r'.results[] | "\(.id) \(.title) v\(.version.number)"'
It should print one line per file: id, name and current version. This one is from our test site, where the file was still at v2:
text
1att380698656 price-list.csv v2
If you used the PUT in Step 3, the id is already the first field it printed. Then list the versions. The call should print three lines, newest first:
13 2026-10-02T21:05:25.239Z (Sentinel Vault automatically reversed modifications) minorEdit=true
22 2026-10-02T21:05:20.666Z Updated A-100 price minorEdit=false
31 2026-10-02T20:56:13.026Z Signed Q4 list minorEdit=false
That's your revert time. Read it off the timestamps. Version 2 landed at 21:05:20.666 and version 3 at 21:05:25.239, so 4.6 seconds. The other two production runs came in at 2.6 and 2.8. The app marks its own upload as a minor edit.
(Hashes shortened.) Versions 1 and 3 match. Version 2 is the one that got rejected. Same bytes, proven. Keep the -L. Without it, Confluence answers 302 (we checked) and you hash a redirect. Jira does the same with a 303, written up in Jira attachment download: 303, not your file.
Step 6: Release the seal to unlock the attachment
When the file is allowed to change again, release it. Don't leave seals lying around. Click Sealed (1) in the byline (or open ⋯, Apps, Seal attachments… again) and press Release on the file's row. On a site with signed actions, you'll type a code here too.
The Overview tab then reads "SEALS ON THIS PAGE · 0", and the activity list says you unsealed the file.
We uploaded once more after releasing and waited 30 seconds. The upload stayed. Unlocked. If you'd rather not release by hand, don't: a seal stops enforcing the moment its time runs out. After that the owner sees an overdue notice on the page once a day, and after the third one the app releases the seal (those are the defaults; reminder comments need the app's comment switch on).
Give one person edit access instead of unlocking (optional)
Sometimes one colleague needs to change the file and nobody else should. Releasing is the wrong tool for that. Don't. On the Overview tab, open the file row's ⋯ and choose Give edit access…, then pick the person.
What we measured: Gabriela's upload after the grant stayed, and it became the new sealed version. When her access was revoked (under "Editors with access" in the full attachments view), her next upload was reverted to her granted version, not to my original. A grant moves the seal forward. That's the behaviour I want. Someone without edit access can press Request edit on the file instead. That one we only read in the code, not tested from the requester's seat.
If it didn't work
You sealed it, uploaded a fix yourself, and the next overwrite brought back the old file. That's my bug, in 6.6.0. Your own upload is allowed, but the seal doesn't adopt it as the new sealed version. In our run my account uploaded v4 with a correction. Gabriela's account then uploaded v5, and the app restored v1's bytes as v6. My correction was still in the history, but it wasn't current anymore. That one's on me. My app, my bug. The workaround: after uploading your own new version, press Release and seal the file again. The new seal adopts your version. Releasing drops any edit access you gave, and the new seal starts a fresh duration, so give access again afterwards. It's logged for a fix, and until one ships, do it that way.
"Attachment is already sealed by another user". Somebody got there first. Ask them for edit access, or wait for the seal to run out. An expired seal from someone else is cleared when you seal.
"You do not have permission to seal this file". You can view the page but not edit it. Sealing follows Confluence's own edit permission: the dialog still opens, but the server refuses anyone who can't edit the page.
"This page is Approved — only its approvers or a space admin can seal on it." The page is Approved in a Sentinel Vault workflow. Ask an approver, or seal before approval.
"Set up your signature first". Your site signs seal actions. Use Set up on My work, scan the QR code with an authenticator app, type the first code and come back. Five wrong codes lock signing for 15 minutes.
Someone renamed the file and nothing was reverted. Correct, renames aren't reverted. We tested it on our test site's development build: the rename stuck. But the next overwrite of the renamed file was reverted to the sealed bytes. The seal follows the attachment id, so the content is still protected under its new name.
Someone moved the file to the trash. That one comes back. Fast. Gabriela's account deleted the sealed file over the API, and it was current again within two seconds, with no new version. If the person who sealed it trashes it, though, the seal is released along with it.
The upload was never reverted. Check the seal hasn't expired: an expired seal stops enforcing at once, even though it stays listed until the app releases it about three days later. If the revert itself fails (the app gives up after three attempts), the owner gets a notice saying so. There's no later sweep that catches a missed upload. Read that notice.
What a seal does not do
A seal protects a file's content, not who can read it. Everyone who can see the page can still view and download the sealed file. If you need that restricted, it's a Confluence page restriction, not a seal.
It doesn't stop the save. For a few seconds the rejected file is the current version, and anyone who downloads it in that window gets the rejected file.
Seals made through Sentinel Vault's own REST API skip the authenticator check, even on a site that signs everything else. So does a sealed section created by inserting the macro in the editor. If your auditors care about signatures, keep sealing in the UI. I would.
And it isn't a check-out tool. Tools like Lockpoint are built around checking a file out before you edit it, and Sentinel Vault has no check-out at all. It lets the upload in and puts the sealed file back. For a signed price list or a contract, putting it back is exactly what you want. For a team that edits the same Word file all day, it's the wrong tool. I'd tell you that before you buy it.
There's more in the app, like section seals, approvals and the AI review, and it's all on the Sentinel Vault page. For locking attachments, the six steps above are the whole job. That's it.
What you have now
Key takeaways
You have a file sealed on a Confluence Cloud page, an overwrite by a second account reverted in seconds, both versions in the attachment history and in the REST API, and the seal released.
The path is ⋯, Apps, Seal attachments…. Anyone who can edit the page can seal, unless the page is Approved in a workflow.
A seal reverts, it doesn't block. The rejected upload stays in the history, and the app's version carries "(Sentinel Vault automatically reversed modifications)".
Prove a revert with GET /wiki/api/v2/attachments/{id}/versions and a sha256 of each version. Keep -L on the download.
Give edit access when one person should change the file. Their upload becomes the new sealed version.
In 6.6.0, after uploading your own new version of a file you sealed, release and seal again.
Confluence data classification without Guard: Sentinel Vault 6 levels from Assets