🛡️ CVE-2026-28508 — known
Description
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)](https://cwe.mitre.org/data/definitions/918.html)
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](https://www.first.org/cvss/calculator/4.0#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)
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:
```php
//$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:
```php
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():
```php
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:
```php
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:
```php
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:
```php
$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 X-IDNO-SIGNATURE headers are present, regardless of whether the supplied credentials are valid. The HMAC verification that follows is therefore irrelevant — by the time tokenGatekeeper() calls validateToken(), the API flag is already set and the token check returns true immediately.
An attacker supplying any non-empty values for these two headers — real or fabricated — bypasses CSRF protection entirely.
Step 4 — The unfurl fetch
With both gatekeepers bypassed, execution reaches UnfurledUrl::unfurl() (UnfurledUrl.php:53):
```php
public function unfurl($url)
{
$url = trim($url);
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
$contents = \Idno\Core\Webservice::file_get_contents($url);
...
$this->data = $unfurled;
$this->source_url = $url;
return true;
}
```
FILTER_VALIDATE_URL accepts any valid URL including http://localhost/, http://169.254.169.254/, and http://10.0
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality high, integrity none, availability none.
Weakness class
CVE-2026-28508 is classified as CWE-918: Server-Side Request Forgery (SSRF). The server fetches a URL supplied by the caller, which can be pointed at internal systems it alone can reach.
Affected software
CVE-2026-28508 is recorded against 2 packages.
- idno/known (fixed in 1.6.4)
- known (fixed in 1.6.4)
Timeline and source
Published on 2 March 2026 and last revised on 6 March 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.
References
github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
github.com (Web)
Details
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| idno/known | — | 1.6.4 |
| known | — | 1.6.4 |
References
Similar Threats
- High CVE-2026-28507
- Critical CVE-2026-26273
- Medium CVE-2022-30852
- Medium CVE-2022-31290
- Medium CVE-2022-32115
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Exploit Protection
Are you running known?
CVE-2026-28508 carries CVSS 9.5 Critical rating. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.
Check My Site For CVE-2026-28508 →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.