CVE-2026-55891
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.
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
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 None
CVSS: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
- 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). - The server reflects the raw value into the JSON-LD response, producing a syntactically broken / attacker-extended JSON document.
- Because
Access-Control-Allow-Origin: *is set andX-Content-Type-Options: nosniffis 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 None
CVSS: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 None
CVSS: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 None
CVSS: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
- 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). - The server reflects the raw value into the JSON-LD response, producing a syntactically broken / attacker-extended JSON document.
- Because
Access-Control-Allow-Origin: *is set andX-Content-Type-Options: nosniffis 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 None
CVSS: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
| Package | Affected | Fixed |
|---|---|---|
privatebin/privatebinPackagist |
through 2.0.4 | 2.0.5 |
privatebin/privatebinPackagist |
before 2.0.5, plus listed versions 1.01.11.1.11.21.2.1 Show 30 moreShow less1.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
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE 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
github.com/PrivateBin/PrivateBin/security/advisories/GHSA-xrjc-c68j-hp7w
github.com/PrivateBin/PrivateBin/commit/164c839c39688533ef0086575878e8392cd21249
github.com/PrivateBin/PrivateBin/releases/tag/2.0.5
github.com/PrivateBin/PrivateBin/commit/75f056dcda955d94c17ec5a4f8c54a9b7bfcee07
github.com/advisories/GHSA-xrjc-c68j-hp7w
github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55891.json
nvd.nist.gov/vuln/detail/CVE-2026-55891
github.com/PrivateBin/PrivateBin
Left out here: the rest of 2 source descriptions. The JSON record has them.