CVE-2026-28508
Idno: Unauthenticated SSRF via URL Unfurl Endpoint
Idno is a social publishing platform. Prior to version 1.6.4, a logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content. This issue has been patched in version 1.6.4.
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
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
9.2
Idno: Unauthenticated SSRF via URL Unfurl Endpoint
Idno is a social publishing platform. Prior to version 1.6.4, a logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content. This issue has been patched in version 1.6.4.
- Record
CVE-2026-28508- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-9984
9.2
Idno is a social publishing platform. Prior to version 1.6.4, a logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content. This issue has been patched in version 1.6.4.
- Record
EUVD-2026-9984- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-fcrh-fqxh-6fx6
9.2
Idno Vulnerable to Unauthenticated SSRF via URL Unfurl Endpoint
Summary
A logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content.
Component: Idno/Pages/Service/Web/UrlUnfurl.php, Idno/Core/Session.php, Idno/Core/Actions.php
Vulnerability Class: Server-Side Request Forgery (SSRF)
Authentication Required: None
CVSSv4 Base Score: 9.2 (High) - AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
Affected Endpoint: GET /service/web/unfurl?url=<attacker-controlled-url>
Handled by Idno\Pages\Service\Web\UrlUnfurl::getContent().
Affected Versions: <= 1.6.3
cat version.idno
version = '1.6.3'
build = 2026021301
Code Flow
Step 1 — Endpoint access control
UrlUnfurl::getContent() (UrlUnfurl.php:36) enforces two access controls:
$this->xhrGatekeeper();
$this->tokenGatekeeper();
Notably, the original authentication check ($this->gatekeeper()) was explicitly removed with the following comment left in the source:
//$this->gatekeeper(); // Gatekeeper to ensure this service isn't abused by third parties
// UPDATE: Needs to be accessible to logged out users, TODO, find a way to prevent abuse
This leaves the endpoint accessible to unauthenticated users, with only the two remaining gatekeepers as a barrier.
Step 2 — Bypassing xhrGatekeeper()
Page::xhrGatekeeper() (Page.php:876) checks whether the request was made with the X-Requested-With:
XMLHttpRequest header:
function xhrGatekeeper()
{
if (!$this->xhr) {
$this->deniedContent();
}
}
This check is trivially bypassed by any HTTP client capable of setting custom headers.
Step 3 — Bypassing tokenGatekeeper() via premature API flag
Page::tokenGatekeeper() (Page.php:887) calls Actions::validateToken():
function tokenGatekeeper()
{
$url = $this->currentUrl();
$bits = explode('?', $url);
$url = $bits[0];
if (!\Idno\Core\Idno::site()->actions()->validateToken($url, false)) {
$this->deniedContent();
}
}
Actions::validateToken() (Actions.php:23) short-circuits entirely when isAPIRequest() returns true:
public static function validateToken($action = '', $haltExecutionOnBadRequest = true)
{
if (Idno::site()->session()->isAPIRequest()) {
return true;
}
return parent::validateToken($action, $haltExecutionOnBadRequest);
}
isAPIRequest() reads the is_api_request flag from the session:
function isAPIRequest()
{
if (!empty($_SESSION['is_api_request'])) {
return true;
}
return false;
}
The flag is set in Session::tryAuthUser() (Session.php:488), which runs early in the request lifecycle. The critical defect is here:
$apiUsername = $_SERVER['HTTP_X_IDNO_USERNAME'] ?? $_SERVER['HTTP_X_KNOWN_USERNAME'] ?? null;
$apiSignature = $_SERVER['HTTP_X_IDNO_SIGNATURE'] ?? $_SERVER['HTTP_X_KNOWN_SIGNATURE'] ?? null;
if (!$return && !empty($apiUsername) && !empty($apiSignature)) {
$this->setIsAPIRequest(true); // ← flag set here, before any credential check
$user = \Idno\Entities\User::getByHandle($apiUsername);
if (!empty($user)) {
$compare_hmac = base64_encode(hash_hmac('sha256', $_SERVER['REQUEST_URI'], $key, true));
if ($hmac == $compare_hmac) { // ← HMAC verified here, too late
$return = $this->refreshSessionUser($user);
}
}
}
setIsAPIRequest(true) is called unconditionally as soon as both X-IDNO-USERNAME and…
- Record
GHSA-fcrh-fqxh-6fx6- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
9.2
Idno is a social publishing platform. Prior to version 1.6.4, a logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content. This issue has been patched in version 1.6.4.
- Record
CVE-2026-28508- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
9.2
Idno: Unauthenticated SSRF via URL Unfurl Endpoint
Idno is a social publishing platform. Prior to version 1.6.4, a logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content. This issue has been patched in version 1.6.4.
- Record
CVE-2026-28508- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVGHSA-fcrh-fqxh-6fx6
9.2
Idno Vulnerable to Unauthenticated SSRF via URL Unfurl Endpoint
Summary
A logic error in the API authentication flow causes the CSRF protection on the URL unfurl service endpoint to be trivially bypassed by any unauthenticated remote attacker. Combined with the absence of a login requirement on the endpoint itself, this allows an attacker to force the server to make arbitrary outbound HTTP requests to any host, including internal network addresses and cloud instance metadata services, and retrieve the response content.
Component: Idno/Pages/Service/Web/UrlUnfurl.php, Idno/Core/Session.php, Idno/Core/Actions.php
Vulnerability Class: Server-Side Request Forgery (SSRF)
Authentication Required: None
CVSSv4 Base Score: 9.2 (High) - AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
Affected Endpoint: GET /service/web/unfurl?url=<attacker-controlled-url>
Handled by Idno\Pages\Service\Web\UrlUnfurl::getContent().
Affected Versions: <= 1.6.3
cat version.idno
version = '1.6.3'
build = 2026021301
Code Flow
Step 1 — Endpoint access control
UrlUnfurl::getContent() (UrlUnfurl.php:36) enforces two access controls:
$this->xhrGatekeeper();
$this->tokenGatekeeper();
Notably, the original authentication check ($this->gatekeeper()) was explicitly removed with the following comment left in the source:
//$this->gatekeeper(); // Gatekeeper to ensure this service isn't abused by third parties
// UPDATE: Needs to be accessible to logged out users, TODO, find a way to prevent abuse
This leaves the endpoint accessible to unauthenticated users, with only the two remaining gatekeepers as a barrier.
Step 2 — Bypassing xhrGatekeeper()
Page::xhrGatekeeper() (Page.php:876) checks whether the request was made with the X-Requested-With:
XMLHttpRequest header:
function xhrGatekeeper()
{
if (!$this->xhr) {
$this->deniedContent();
}
}
This check is trivially bypassed by any HTTP client capable of setting custom headers.
Step 3 — Bypassing tokenGatekeeper() via premature API flag
Page::tokenGatekeeper() (Page.php:887) calls Actions::validateToken():
function tokenGatekeeper()
{
$url = $this->currentUrl();
$bits = explode('?', $url);
$url = $bits[0];
if (!\Idno\Core\Idno::site()->actions()->validateToken($url, false)) {
$this->deniedContent();
}
}
Actions::validateToken() (Actions.php:23) short-circuits entirely when isAPIRequest() returns true:
public static function validateToken($action = '', $haltExecutionOnBadRequest = true)
{
if (Idno::site()->session()->isAPIRequest()) {
return true;
}
return parent::validateToken($action, $haltExecutionOnBadRequest);
}
isAPIRequest() reads the is_api_request flag from the session:
function isAPIRequest()
{
if (!empty($_SESSION['is_api_request'])) {
return true;
}
return false;
}
The flag is set in Session::tryAuthUser() (Session.php:488), which runs early in the request lifecycle. The critical defect is here:
$apiUsername = $_SERVER['HTTP_X_IDNO_USERNAME'] ?? $_SERVER['HTTP_X_KNOWN_USERNAME'] ?? null;
$apiSignature = $_SERVER['HTTP_X_IDNO_SIGNATURE'] ?? $_SERVER['HTTP_X_KNOWN_SIGNATURE'] ?? null;
if (!$return && !empty($apiUsername) && !empty($apiSignature)) {
$this->setIsAPIRequest(true); // ← flag set here, before any credential check
$user = \Idno\Entities\User::getByHandle($apiUsername);
if (!empty($user)) {
$compare_hmac = base64_encode(hash_hmac('sha256', $_SERVER['REQUEST_URI'], $key, true));
if ($hmac == $compare_hmac) { // ← HMAC verified here, too late
$return = $this->refreshSessionUser($user);
}
}
}
setIsAPIRequest(true) is called unconditionally as soon as both X-IDNO-USERNAME and…
- Record
GHSA-fcrh-fqxh-6fx6- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - Weakness
- CWE-918
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
idno/knownPackagist |
through 1.6.3 | 1.6.4 |
idno/knownPackagist |
before 1.6.4, plus listed versions 1.0.01.0.0-rc.11.0.0-rc.31.2.21.51.6.21.6.3 |
1.6.4 |
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-28508 is a critical vulnerability (CVSS 9.2) in Idno, published March 2, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.71%, the 53rd percentile. Fixed in idno/known 1.6.4.
References
Left out here: the rest of 2 source descriptions. The JSON record has them.