XSS via unescaped data injected into map.php script block and Leaflet popup #2

Open
opened 2026-05-14 20:35:01 +02:00 by Claude · 0 comments

Problem

map.php embeds PHP data directly into a <script> block using json_encode without the JSON_HEX_TAG flag. PHP's default json_encode does not escape < and >, so a takenAt value containing </script> in the BeReal export JSON would terminate the script tag and allow injecting arbitrary HTML/JavaScript into the page.

Additionally, the Leaflet popup HTML is built by raw string concatenation on the JavaScript side with no sanitization:

const popup = '<b>' + (p.at || '') + '</b>'
  + (p.thumb ? '<br><a href="' + p.thumb + '"...><img src="' + p.thumb + '"...></a>' : '');
m.bindPopup(popup);

bindPopup interprets its argument as HTML, so any HTML in p.at is executed as markup.

Location

map.php — PHP JSON embedding (~line 22):

const points = <?= json_encode($points, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) ?>;

And the JavaScript popup builder (~lines 33–36).

Risk

A maliciously crafted BeReal export with an invalid or injected takenAt field (where fmt_date() falls back to returning the raw string) or a field containing </script> could inject and execute JavaScript in the browser of whoever views the map page. For a local viewer this is lower severity, but it violates the principle that data from the export should never reach the DOM unescaped.

Suggested fix direction

Add JSON_HEX_TAG to the json_encode call so < and > are emitted as </>. On the JavaScript side, use document.createTextNode / .textContent assignments or a safe templating approach instead of HTML string concatenation for popup content.

Severity

moderate

Found by

Automated audit by Claude Code

## Problem `map.php` embeds PHP data directly into a `<script>` block using `json_encode` without the `JSON_HEX_TAG` flag. PHP's default `json_encode` does **not** escape `<` and `>`, so a `takenAt` value containing `</script>` in the BeReal export JSON would terminate the script tag and allow injecting arbitrary HTML/JavaScript into the page. Additionally, the Leaflet popup HTML is built by raw string concatenation on the JavaScript side with no sanitization: ```js const popup = '<b>' + (p.at || '') + '</b>' + (p.thumb ? '<br><a href="' + p.thumb + '"...><img src="' + p.thumb + '"...></a>' : ''); m.bindPopup(popup); ``` `bindPopup` interprets its argument as HTML, so any HTML in `p.at` is executed as markup. ## Location `map.php` — PHP JSON embedding (~line 22): ```php const points = <?= json_encode($points, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) ?>; ``` And the JavaScript popup builder (~lines 33–36). ## Risk A maliciously crafted BeReal export with an invalid or injected `takenAt` field (where `fmt_date()` falls back to returning the raw string) or a field containing `</script>` could inject and execute JavaScript in the browser of whoever views the map page. For a local viewer this is lower severity, but it violates the principle that data from the export should never reach the DOM unescaped. ## Suggested fix direction Add `JSON_HEX_TAG` to the `json_encode` call so `<` and `>` are emitted as `<`/`>`. On the JavaScript side, use `document.createTextNode` / `.textContent` assignments or a safe templating approach instead of HTML string concatenation for popup content. ## Severity moderate ## Found by Automated audit by Claude Code
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bc1bb/BeReal-extractor#2
No description provided.