RapidWeaver backups and security through obscurity

So, I have attached Claude (Fable 5.1) via MCP to Elements. :grinning_face:

I got it to review my project and one of the issues it identified was:

:red_circle: Critical — Project backup zip exposed (reported earlier): full .elements project publicly downloadable from the live site, including contact-form SMTP password and FTP username.

I asked:

I have copied the backup to my Mac’s desktop and deleted the backup on the server. The create a backup on publish is a standard RapidWeaver Elements function. Isn’t having a random uuid in the filename secure enough and if not, why?

Claude replied:

Good — deleting it removes the immediate exposure. To answer the question directly: a random UUID in the path is a reasonable defence against guessing, but it’s not a substitute for access control, because the URL only has to leak once and there are several ordinary ways it can.

Why “unguessable” isn’t the same as “protected”:

The name is only as secret as every place it’s ever been written. That UUID appears in your project’s data.json, in .DS_Store files (which Elements publishes alongside the site — the local publish folder had one), in the FTP client’s transfer logs, in the host’s access logs if you ever opened it in a browser, in browser history, and in any screen share or support ticket. It only needs to appear once in something that gets shared, indexed, or backed up somewhere less private.
Directory listing and misconfiguration. The folder returned 404 for a listing, which is good, but that’s a property of the server config — a hosting migration, a cPanel change, or a .htaccess edit could turn listing on and the file becomes visible with no URL knowledge required. Security-by-obscurity fails silently when the assumption behind it changes.
The UUID is stable. It’s the project’s identity, not a per-publish nonce, so it never rotates. Once known, it’s known forever, and Elements refreshes the zip on every publish, so a leaked URL yields an always-current copy of the whole project.
The payload is disproportionate to the protection. A URL nobody is meant to see is fine for, say, a temporary preview image. Here it guards the FTP username, the contact form’s SMTP password, the form spam key, and the full source of every members-only admin page. The blast radius if the obscurity fails is total, so it deserves real access control, not just a hard-to-guess name.
Scanners do find things. Automated crawlers and bug-bounty tooling routinely check for _rwbackup-style patterns; RapidWeaver’s backup folder naming (_rwbackup/) is publicly known, and a scanner only needs the UUID, which brings us back to the first point.
What “secure enough” would look like, if you want to keep the feature on: have Elements publish the backup but block it from the web — a .htaccess in that folder with Require all denied (Elements can publish that as a code file), so the zip lands on the server for disaster recovery but returns 403 to any browser. That keeps the convenience with none of the exposure. Alternatively, leave the feature off for the Prod destinations and rely on your existing Keyboard Maestro/CCC source-backup scheme, which already covers the project.

Two things I’d still do regardless: rotate the contact form’s SMTP password and spam secret key (they were in a zip that was public for at least some period), and if the backup-on-publish setting is still on, delete the folder again after your next publish — Elements will have recreated it.

So I have taken Claude’s advice and removed the backup.

So @dan / @tpbradley, what do you think about Claude’s advice. I have erred on the side of caution for the moment. :wink:

This is the way it’s been done since the backup feature was released way back when. In order for the backup file to be accessible not only would the folder name have to be brute forced, but the filename as well.

You (or Claude) makes a good point however. A counterpoint (also from Claude) is below:

Thanks for raising this — it’s a fair thing to double-check, and I appreciate you thinking it through rather than just assuming it’s fine.

The short version: guessing that folder name isn’t practically possible. It’s not a made-up string or a simple random name — it’s a UUID (specifically version 4), which means it’s generated with 122 bits of actual randomness. To put that in perspective, that’s about 5.3 × 10³⁶ possible combinations. Even if someone could somehow fire off a million guesses a second at a web server continuously (which isn’t realistic — servers would throttle or block that kind of traffic long before it mattered), it would still take on the order of 10²³ years to work through the possibilities. The universe is about 14 billion years old, so this isn’t “difficult,” it’s off-the-charts impossible with current or foreseeable computing.

So brute-forcing the name isn’t a realistic threat model here. The more realistic way a URL like this could ever be exposed isn’t guessing — it’s leakage. For example:

  • Pasting the direct link somewhere public (a forum post, a support ticket, a screenshot) without realizing it’s a live link
  • A browser sending that URL along as a referrer if it were ever linked from another page
  • The link ending up in analytics or logging somewhere it shouldn’t

None of those are things an attacker can do proactively — they all require the link to leak out through user action first. As long as the URL itself isn’t shared or embedded anywhere, it functions the same as a private, unguessable credential.

That said, “security through obscurity” as a sole layer is a valid thing to be cautious about in general, so it’s a good instinct to question it. If you want extra peace of mind, the practical thing to check on your own hosting is whether directory listing is disabled for that folder — that way, even if someone found the folder name through some other means, they couldn’t browse it to find the filename.

Happy to go into more detail if you want it — glad you brought it up rather than just wondering.

One thing that your Fable’s assessment missed is this:

What “secure enough” would look like, if you want to keep the feature on: have Elements publish the backup but block it from the web — a .htaccess in that folder with Require all denied (Elements can publish that as a code file), so the zip lands on the server for disaster recovery but returns 403 to any browser.

That’s assuming the web hosting provider is using a web server that supports .htaccess files (Apache, LiteSpeed). If the user is hosting with a provider using NGINX, that .htaccess file wouldn’t do anything as NGINX doesn’t support .htaccess files.

The point of the built-in backups feature is that your project file is stored on the web hosting server, along with the project file on your Mac, so you have redundancy in case something happens to your Mac and you lose the project file there. RapidWeaver needs to be able to access that backup file in order to download it back into the app so you can keep working on it. In order to do that, it needs permissions to access the file.

With all that said, I imagine there a way it could be made extra secure. :slightly_smiling_face:

The backup is stored inside a UUID-named folder and is not linked from the published site. Brute-forcing that UUID is not a realistic way to discover it. That’s just not going to happen.

Claude is right about the narrower point that the exact URL should be treated like a secret. If somebody obtains the complete URL, they could download the archive. But, as long as you don’t share the UUID, you’re fine.

AI worked out how long it’d take to brute force this…

Even if an attacker already knew the exact project filename and could make one million guesses every second, it would take an average of around 84,241,386,910,596,235,005,438 years to find the UUID folder. The realistic risk is the complete URL being shared or leaked, not someone successfully guessing it.

Maybe Elements should offer the option to zip it with a password?

If you have security concerns, I’d recommend making local backups instead.

I didn’t until Elements AI MCP and Claude told me I should have. :wink:

It’s an interesting idea. Elements would have to store that password then in order to unzip it when a user downloads it back into the app. :thinking:

A question for @tpbradley for sure if that’s technically feasible.

In the meantime, if your web host supports .htaccess files, you can add Options -Indexes to your root .htaccess file to disable directory browsing. Then for extra caution you can give your project file a hard to guess name (like append some randomly generated text onto the end of the filename) so that not only would that folder UUID have to be brute-forced (which is realistically impossible per the prior posts in this thread), but then your backup filename would also have to be brute-forced as well.

Or just disable backups in RapidWeaver’s publishing settings if you want to store your backups offline like @dan mentioned. That’s the most secure way to do it.

It should be easy to do with a public key / private key pair? Anyway, I am already backing up my encrypted project to an offsite account. So I will leave Elements backup turned off for the moment.