Every CVE Search/ Get API key

CVE-2026-55891

PrivateBin: Reflected JSON injection in backend responses via unescaped REQUEST_URI

0.0 NoneFix available

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['REQUEST_URI'] through FILTER_SANITIZE_URL, 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 str_replace() 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.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
None

Exploit likelihood

0.54%Up 0.2 points since Aug 29, 2026
90%50%10%1%

What each source reports

CVE List Score used 0.0

PrivateBin: Reflected JSON injection in backend responses via unescaped REQUEST_URI

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['REQUEST_URI'] through FILTER_SANITIZE_URL, 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 str_replace() 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.

Record
CVE-2026-55891
CVSS 3.1
0.0 NoneCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Weakness
CWE-116
Updated
2026-11-02
EUVDEUVD-2026-67940 No score

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['REQUEST_URI'] through FILTER_SANITIZE_URL, 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 str_replace() 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.

Record
EUVD-2026-67940
Updated
2026-11-02
GitHub AdvisoriesGHSA-xrjc-c68j-hp7w 0.0

PrivateBin has reflected JSON injection in backend responses via unescaped REQUEST_URI

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['REQUEST_URI'] with FILTER_SANITIZE_URL:

public function getRequestUri()
{
    $uri = array_key_exists('REQUEST_URI', $_SERVER) ? filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL) : '';
    return empty($uri) ? '/' : $uri;
}

FILTER_SANITIZE_URL 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 str_replace(), without any JSON-escaping:

$content = str_replace(
    '?jsonld=',
    $this->_urlBase . '?jsonld=',
    file_get_contents($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:

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

$content = str_replace(
    '?jsonld=',
    $this->_urlBase . '?jsonld=',
    file_get_contents($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:

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

Unpatched response body (excerpt):

"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…

Record
GHSA-xrjc-c68j-hp7w
CVSS 3.1
0.0 NoneCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Weakness
CWE-116
Updated
2026-11-02
NVD 0.0

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['REQUEST_URI'] through FILTER_SANITIZE_URL, 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 str_replace() 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.

Record
CVE-2026-55891
CVSS 3.1
0.0 NoneCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Weakness
CWE-116
Updated
2026-11-02
OSV 0.0

PrivateBin: Reflected JSON injection in backend responses via unescaped REQUEST_URI

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['REQUEST_URI'] through FILTER_SANITIZE_URL, 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 str_replace() 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.

Record
CVE-2026-55891
CVSS 3.1
0.0 NoneCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Weakness
CWE-116
Updated
2026-11-02
OSVGHSA-xrjc-c68j-hp7w 0.0

PrivateBin has reflected JSON injection in backend responses via unescaped REQUEST_URI

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['REQUEST_URI'] with FILTER_SANITIZE_URL:

public function getRequestUri()
{
    $uri = array_key_exists('REQUEST_URI', $_SERVER) ? filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL) : '';
    return empty($uri) ? '/' : $uri;
}

FILTER_SANITIZE_URL 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 str_replace(), without any JSON-escaping:

$content = str_replace(
    '?jsonld=',
    $this->_urlBase . '?jsonld=',
    file_get_contents($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:

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

$content = str_replace(
    '?jsonld=',
    $this->_urlBase . '?jsonld=',
    file_get_contents($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:

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

Unpatched response body (excerpt):

"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…

Record
GHSA-xrjc-c68j-hp7w
CVSS 3.1
0.0 NoneCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Weakness
CWE-116
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
privatebin/privatebin
Packagist
through 2.0.4
2.0.5
privatebin/privatebin
Packagist
before 2.0.5, plus listed versions
1.01.11.1.11.21.2.1
Show 30 moreShow less
1.2.21.2.31.31.3.11.3.21.3.31.3.41.3.51.4.01.5.01.5.11.5.21.6.01.6.11.6.21.7.01.7.11.7.21.7.31.7.41.7.51.7.61.7.71.7.81.7.92.0.02.0.12.0.22.0.32.0.4
2.0.5

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-55891 is a none vulnerability (CVSS 0.0) in Privatebin, published August 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.54%, the 45th percentile. Fixed in privatebin/privatebin 2.0.5.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open