CVE-2026-55891: PrivateBin: Reflected JSON injection in backend responses via unescaped REQUEST_URI

Published Aug 28, 2026
·
Updated

Vulnerability Details

A reflected JSON injection allows an attacker to return arbitrary data in the JSON endpoints (like /?jsonld= and /?pasteid).

Root Cause

Request::getRequestUri() sanitizes $SERVER['REQUESTURI'] with FILTERSANITIZEURL:

php public function getRequestUri() { $uri = arraykeyexists('REQUESTURI', $SERVER) ? filtervar($SERVER['REQUESTURI'], FILTERSANITIZEURL) : ''; return empty($uri) ? '/' : $uri; }

FILTERSANITIZEURL does not strip ", ', <, > characters (per the PHP manual's allowed-character list for this filter). So the raw, attacker-controlled request URI (including query string) passes through almost unmodified into Controller::$urlBase (set in init()).

In Controller::jsonld(), $urlBase is spliced directly into one of the static .jsonld templates (js/types.jsonld, js/paste.jsonld, etc.) with a plain strreplace(), without any JSON-escaping:

php $content = strreplace( '?jsonld=', $this->urlBase . '?jsonld=', filegetcontents($file) ); ... header('Content-type: application/ld+json'); header('Access-Control-Allow-Origin: '); header('Access-Control-Allow-Methods: GET'); echo $content;

A request URI containing a literal " therefore breaks out of the JSON string in the "@context"."pb" value and injects arbitrary attacker-controlled key/value pairs into the response body, which is served with Content-Type: application/ld+json and Access-Control-Allow-Origin: .

Additionally, the jsonld case in Controller::construct() returns early:

php case 'jsonld': $this->jsonld($this->request->getParam('jsonld')); return;

This bypasses setCacheHeaders() and all of the security headers normally applied in view() (notably X-Content-Type-Options: nosniff, CSP, X-Frame-Options, Referrer-Policy). So this is the only response path lacking X-Content-Type-Options: nosniff.

Attack Scenario 1. An attacker crafts a request to the target PrivateBin instance whose request-target contains a raw " character, e.g.: GET /?jsonld=types&x="injected":"pwned","y":" HTTP/1.1 (delivered via a raw socket / HTTP client that doesn't normalize the request line — most browsers percent-encode " in the address bar, but many HTTP libraries, proxies, and automated link-preview/structured-data crawlers do not). 2. The server reflects the raw value into the JSON-LD response, producing a syntactically broken / attacker-extended JSON document. 3. Because Access-Control-Allow-Origin: is set and X-Content-Type-Options: nosniff is missing on this path, any origin can fetch and rely on this manipulated content, and the response loses the defense-in-depth MIME-sniffing protection applied everywhere else in the app.

Impact Reflected, unauthenticated injection of attacker-controlled content into a CORS-open application/ld+json response, plus a missing X-Content-Type-Options: nosniff header on this single response path (present everywhere else). No direct script execution was demonstrated on current browsers (this content type is generally not HTML-sniffed), but it is a real output-encoding bug (CWE-116) and a defense-in-depth gap that could be exploited by structured-data consumers or in combination with other issues / less-strict clients.

Vulnerable Code php $content = strreplace( '?jsonld=', $this->urlBase . '?jsonld=', filegetcontents($file) ); ... header('Content-type: application/ld+json');

Verification Dynamically confirmed on v2.0.4 (commit 597a6f0) via php -S 127.0.0.1:8082 index.php:

Request: http GET /?jsonld=types&x="injected":"pwned","y":" HTTP/1.1 Host: 127.0.0.1:8082 Connection: close

Unpatched response body (excerpt): json "pb": "/?jsonld=types&x="injected":"pwned","y":"?jsonld=types#" — i.e. the " characters are reflected raw, breaking the JSON structure, and X-Content-Type-Options is absent from the response headers.

After applying the fix above, the same request returns: json "pb": "/?jsonld=types&x=\"injected\":\"pwned\",\"y\":\"?jsonld=types#" with X-Content-Type-Options: nosniff present, and the existing JsonApiTest::testJsonLd unit test expectations (/?jsonld=...) remain unchanged for normal requests.

Credits

This vulnerability was reported by Iaohkut, @alanturing881, which PrivateBin would like to thank for that. In general, PrivateBin would like to thank everyone reporting issues and potential vulnerabilities to it.

If you think you have found a vulnerability or potential security risk, we'd kindly ask you to follow our security policy and report it to us. PrivateBin then assess the report and will take the actions PrivateBin deem necessary to address it.

Other sources

PrivateBin is an online pastebin where the server has zero knowledge of pasted data. Prior to 2.0.5, Request::getRequestUri() in lib/Request.php passes $SERVER['REQUESTURI'] through FILTERSANITIZEURL, which does not remove quotation marks, angle brackets, or apostrophes, and Controller::init() stores the attacker-controlled value in Controller::$urlBase. Controller::jsonld() in lib/Controller.php then uses strreplace() to insert that value without JSON escaping into js/types.jsonld, js/paste.jsonld, and the other JSON-LD templates used by /?jsonld= and /?pasteid. A raw quotation mark delivered by an HTTP client, proxy, or structured-data crawler that does not normalize the request target can break out of the JSON string and inject arbitrary key-value data into a CORS-open application/ld+json response. The jsonld branch in Controller::construct() returns before setCacheHeaders(), so the response also lacks X-Content-Type-Options: nosniff, Content Security Policy, X-Frame-Options, and Referrer-Policy. Direct script execution was not demonstrated, but manipulated responses can affect structured-data consumers or combine with less strict clients. This issue is fixed in version 2.0.5.

MITRE

Affected Software

1 affected componentFixes available
composer/privatebin/privatebin<=2.0.4
2.0.5

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade composer/privatebin/privatebin to a version that resolves this vulnerability.

    Fixed in 2.0.5
  2. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 2.0.5
  3. Configuration

    On the jsonld branch (/ ?jsonld=... and /?pasteid responses), ensure the response includes header `X-Content-Type-Options: nosniff` (the issue occurs because this path returns early before `_setCacheHeaders()` / `_view()` applies security headers).

    PrivateBin jsonld response path (Controller::__construct() -> Controller::_jsonld() / lib/Controller.php) X-Content-Type-Options = nosniff
  4. Configuration

    In `Controller::_jsonld()`, stop using `str_replace()` to splice `$_urlBase` into `js/types.jsonld`, `js/paste.jsonld`, and other JSON-LD templates without JSON escaping; encode/escape the attacker-controlled request-target value so that raw `"` in `REQUEST_URI` cannot break out of the JSON string (CWE-116).

    PrivateBin jsonld output encoding (Controller::_jsonld() / lib/Controller.php) REQUEST_URI insertion into JSON-LD templates = JSON-escaped/encoded
  5. Compensating control

    Because the affected jsonld response is CORS-open (`Access-Control-Allow-Origin: *`) and served as `application/ld+json`, add external compensating controls to limit which origins can fetch/consume this endpoint (e.g., restrict access via network/API gateway rules or CORS/response-header controls in front of PrivateBin), until patched.

Event History

Aug 28, 2026
CVE Published
via MITRE·08:23 PM
Data Sourced
via MITRE·08:23 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·08:25 PM
Data Sourced
via GitHub·08:25 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

What does an attacker need to control to trigger the issue?

The attacker needs to submit a request with a crafted request URI, including its query string. Characters such as double quotes, single quotes, less-than signs, and greater-than signs can survive the URL sanitization used by the affected code path.

2

Which application paths should be assessed for exposure?

Assess JSON responses reached through the jsonld and pasteid query parameters, including request forms such as /?jsonld= and /?pasteid. The JSON-LD handling inserts the request-derived URL base into static .jsonld templates without JSON escaping.

3

Why can this affect clients beyond the requesting browser session?

The affected JSON-LD response is served as application/ld+json and includes Access-Control-Allow-Origin: * with GET allowed. This means cross-origin callers may be able to request and read the affected response where browser CORS rules apply.

4

What remediation information is available in the provided data?

The provided references include a PrivateBin security advisory, commit 75f056dcda955d94c17ec5a4f8c54a9b7bfcee07, and the 2.0.5 release page. The data does not state affected version ranges or provide a documented workaround.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203