One of the features of the Web Share API is that it allows you to share files along with your share intent:
if (navigator.canShare && navigator.canShare({ files: filesArray })) {
navigator.share({
files: filesArray,
title: 'Vacation Pictures',
text: 'Photos from September 27 to October 14.',
})
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
console.log(`Your system doesn't support sharing files.`);
}
As unearthed by redteam.pl there’s a big security issue with it in Safari/MobileSafari:
The problem is that
file:
scheme is allowed and when a website points to such URL unexpected behavior occurs. In case such a link is passed to thenavigator.share
function an actual file from the user file system is included in the shared message which leads to local file disclosure when a user is sharing it unknowingly. The problem is not very serious as user interaction is required, however it is quite easy to make the shared file invisible to the user. The closest comparison that comes to mind is clickjacking as we try to convince the unsuspecting user to perform some action.
In their tests they’ve successfully stolen the local /etc/passwd
or even the entire MobileSafari history (which is nothing more than a .sqlite file).
Apple first stated that they are only going to fix it in the Spring 2021 (!) Security Update, but after the post went public it now looks that they’ve changed course, as by now a fix has been committed into the Webkit Source:
+static Optional<URL> shareableURLForShareData(ScriptExecutionContext& context, const ShareData& data)
+{
+ if (data.url.isNull())
+ return WTF::nullopt;
+
+ auto url = context.completeURL(data.url);
+ if (!url.isValid())
+ return WTF::nullopt;
+ if (!url.protocolIsInHTTPFamily() && !url.protocolIsData())
+ return WTF::nullopt;
+
+ return url;
+}
+
- Optional<URL> url;
- if (!data.url.isNull()) {
- url = context.completeURL(data.url);
- if (!url->isValid())
- return false;
- }
+ if (!data.url.isNull() && !shareableURLForShareData(context, data))
+ return false;
+
Bonus points for naming that class WTF
😅
Apart from that quick fix in the code, the issue is also being discussed at the spec level in order to prevent other implementers from making the same mistake.
🤔 What about Chrome you might ask? Google Chrome (on Android) has an allowlist of permitted file extensions in place.
Stealing local files using Safari Web Share API →
Via Thomas Steiner (@tomayac) on Twitter