CWE-863
Allowed-with-ReviewIncorrect Authorization
Abstraction: Class · Status: Incomplete
The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.
6890 vulnerabilities reference this CWE, most recent first.
GHSA-992G-9CR3-VM5X
Vulnerability from github – Published: 2026-09-22 20:40 – Updated: 2026-09-22 20:40Cross-tenant disclosure risk on DurableTask bidi RPC
This is a low-severity, low-risk cross-tenant data exposure vuln caused by blindly accepting a durable task id, in addition to a list of node and branch ids that identify records in that task's event log, and returning them to the caller via the handleWorkerStatus polling path.
Impact
This advisory requires an attacker to successfully guess a durable task's external uuid belonging to another tenant. External ids are generated uuid v4s (uuid.New() in Go), so exploitation requires prior knowledge of a target task UUID through an out-of-band channel. Thus, while the following environments are impacted, there is an extremely low probability it would be exploited.
Who is impacted. Any Hatchet deployment that hosts more than one tenant on the same instance:
- Hatchet Cloud (multi-tenant SaaS)
- Self-hosted Hatchet with multiple internal teams / business units sharing one instance
- Any deployment where a single tenant's API token can be obtained by an attacker
Single-tenant self-hosted deployments are unaffected in practice (the "victim" and "attacker" tenants would be the same).
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/hatchet-dev/hatchet"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.106.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-88978"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-22T20:40:46Z",
"nvd_published_at": "2026-09-21T16:17:26Z",
"severity": "MODERATE"
},
"details": "# Cross-tenant disclosure risk on `DurableTask` bidi RPC\n\nThis is a low-severity, low-risk cross-tenant data exposure vuln caused by blindly accepting a durable task id, in addition to a list of node and branch ids that identify records in that task\u0027s event log, and returning them to the caller via the `handleWorkerStatus` polling path.\n\n# Impact\n\nThis advisory requires an attacker to successfully guess a durable task\u0027s external uuid belonging to another tenant. External ids are generated uuid v4s (`uuid.New()` in Go), so exploitation requires prior knowledge of a target task UUID through an out-of-band channel. Thus, while the following environments are impacted, there is an extremely low probability it would be exploited.\n\n### Who is impacted. Any Hatchet deployment that hosts more than one tenant on the same instance:\n\n* Hatchet Cloud (multi-tenant SaaS)\n* Self-hosted Hatchet with multiple internal teams / business units sharing one instance\n* Any deployment where a single tenant\u0027s API token can be obtained by an attacker\n\nSingle-tenant self-hosted deployments are unaffected in practice (the \"victim\" and \"attacker\" tenants would be the same).",
"id": "GHSA-992g-9cr3-vm5x",
"modified": "2026-09-22T20:40:46Z",
"published": "2026-09-22T20:40:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/hatchet-dev/hatchet/security/advisories/GHSA-992g-9cr3-vm5x"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-88978"
},
{
"type": "WEB",
"url": "https://github.com/hatchet-dev/hatchet/commit/15bc7923d3a8ebfeb0d88c19160dd24828921e85"
},
{
"type": "PACKAGE",
"url": "https://github.com/hatchet-dev/hatchet"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Hatchet DurableTask WorkerStatus gRPC resolves caller-supplied durable-task UUIDs via ListSatisfiedEntries with no tenant_id filter"
}
GHSA-994M-HVJJ-RV2C
Vulnerability from github – Published: 2026-08-25 21:31 – Updated: 2026-08-28 21:30Incorrect authorization in Network in Google Chrome prior to 152.0.7977.65 allowed a remote attacker to bypass system access restrictions via a crafted HTML page. (Chromium security severity: Medium)
{
"affected": [],
"aliases": [
"CVE-2026-79199"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-25T21:18:13Z",
"severity": "MODERATE"
},
"details": "Incorrect authorization in Network in Google Chrome prior to 152.0.7977.65 allowed a remote attacker to bypass system access restrictions via a crafted HTML page. (Chromium security severity: Medium)",
"id": "GHSA-994m-hvjj-rv2c",
"modified": "2026-08-28T21:30:56Z",
"published": "2026-08-25T21:31:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-79199"
},
{
"type": "WEB",
"url": "https://chromereleases.googleblog.com/2026/08/stable-channel-update-for-desktop_0256176589.html"
},
{
"type": "WEB",
"url": "https://issues.chromium.org/issues/513719741"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-998C-7HF5-G249
Vulnerability from github – Published: 2026-04-08 18:34 – Updated: 2026-04-08 18:34Incorrect Authorization (CWE-863) in Kibana can lead to cross-space information disclosure via Privilege Abuse (CAPEC-122). A user with Fleet agent management privileges in one Kibana space can retrieve Fleet Server policy details from other spaces through an internal enrollment endpoint. The endpoint bypasses space-scoped access controls by using an unscoped internal client, returning operational identifiers, policy names, management state, and infrastructure linkage details from spaces the user is not authorized to access.
{
"affected": [],
"aliases": [
"CVE-2026-33460"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-08T17:21:18Z",
"severity": "MODERATE"
},
"details": "Incorrect Authorization (CWE-863) in Kibana can lead to cross-space information disclosure via Privilege Abuse (CAPEC-122). A user with Fleet agent management privileges in one Kibana space can retrieve Fleet Server policy details from other spaces through an internal enrollment endpoint. The endpoint bypasses space-scoped access controls by using an unscoped internal client, returning operational identifiers, policy names, management state, and infrastructure linkage details from spaces the user is not authorized to access.",
"id": "GHSA-998c-7hf5-g249",
"modified": "2026-04-08T18:34:07Z",
"published": "2026-04-08T18:34:07Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33460"
},
{
"type": "WEB",
"url": "https://discuss.elastic.co/t/kibana-8-19-14-9-2-8-9-3-3-security-update-esa-2026-25/385813"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-99FV-V434-WH6F
Vulnerability from github – Published: 2025-02-12 00:32 – Updated: 2025-02-12 18:31An issue in the SharedConfig class of Telegram Android APK v.11.7.0 allows a physically proximate attacker to bypass authentication and escalate privileges by manipulating the return value of the checkPasscode method.
{
"affected": [],
"aliases": [
"CVE-2024-54916"
],
"database_specific": {
"cwe_ids": [
"CWE-287",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-02-11T23:15:09Z",
"severity": "MODERATE"
},
"details": "An issue in the SharedConfig class of Telegram Android APK v.11.7.0 allows a physically proximate attacker to bypass authentication and escalate privileges by manipulating the return value of the checkPasscode method.",
"id": "GHSA-99fv-v434-wh6f",
"modified": "2025-02-12T18:31:34Z",
"published": "2025-02-12T00:32:17Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-54916"
},
{
"type": "WEB",
"url": "https://drive.google.com/file/d/1knf8-_fFUSLd3ZmbEpy0_OVzSN1UR1JR/view?usp=sharing"
},
{
"type": "WEB",
"url": "https://github.com/SAHALLL/CVE-2024-54916"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-99J9-W4CP-4529
Vulnerability from github – Published: 2022-05-24 17:18 – Updated: 2022-05-24 17:18There is an Incorrect Authorization vulnerability in Micro Focus Service Management Automation (SMA) product affecting version 2018.05 to 2020.02. The vulnerability could be exploited to provide unauthorized access to the Container Deployment Foundation.
{
"affected": [],
"aliases": [
"CVE-2020-11844"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-05-29T22:15:00Z",
"severity": "HIGH"
},
"details": "There is an Incorrect Authorization vulnerability in Micro Focus Service Management Automation (SMA) product affecting version 2018.05 to 2020.02. The vulnerability could be exploited to provide unauthorized access to the Container Deployment Foundation.",
"id": "GHSA-99j9-w4cp-4529",
"modified": "2022-05-24T17:18:54Z",
"published": "2022-05-24T17:18:54Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-11844"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645628"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645629"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645630"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645631"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645636"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03645642"
},
{
"type": "WEB",
"url": "https://support.microfocus.com/kb/doc.php?id=7024637"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-99MR-FJVP-4W9W
Vulnerability from github – Published: 2026-03-26 21:31 – Updated: 2026-03-30 15:31Incorrect Authorization vulnerability in Drupal AI (Artificial Intelligence) allows Resource Injection.This issue affects AI (Artificial Intelligence): from 0.0.0 before 1.1.11, from 1.2.0 before 1.2.12.
{
"affected": [],
"aliases": [
"CVE-2026-3573"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-26T21:17:09Z",
"severity": "HIGH"
},
"details": "Incorrect Authorization vulnerability in Drupal AI (Artificial Intelligence) allows Resource Injection.This issue affects AI (Artificial Intelligence): from 0.0.0 before 1.1.11, from 1.2.0 before 1.2.12.",
"id": "GHSA-99mr-fjvp-4w9w",
"modified": "2026-03-30T15:31:52Z",
"published": "2026-03-26T21:31:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-3573"
},
{
"type": "WEB",
"url": "https://www.drupal.org/sa-contrib-2026-028"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-99PG-5RF4-R9X9
Vulnerability from github – Published: 2022-09-20 00:00 – Updated: 2022-09-22 00:00When the LDAP connector is started with StartTLS configured, unauthenticated access is granted. This issue affects: all versions of the LDAP connector prior to 1.5.20.9. The LDAP connector is bundled with Identity Management (IDM) and Remote Connector Server (RCS)
{
"affected": [],
"aliases": [
"CVE-2022-0143"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-09-19T22:15:00Z",
"severity": "CRITICAL"
},
"details": "When the LDAP connector is started with StartTLS configured, unauthenticated access is granted. This issue affects: all versions of the LDAP connector prior to 1.5.20.9. The LDAP connector is bundled with Identity Management (IDM) and Remote Connector Server (RCS)",
"id": "GHSA-99pg-5rf4-r9x9",
"modified": "2022-09-22T00:00:25Z",
"published": "2022-09-20T00:00:21Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0143"
},
{
"type": "WEB",
"url": "https://backstage.forgerock.com/downloads/browse/idm/featured/connectors"
},
{
"type": "WEB",
"url": "https://backstage.forgerock.com/knowledge/kb/article/a11380515"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-99QV-G4X9-MGC3
Vulnerability from github – Published: 2026-05-06 20:45 – Updated: 2026-06-09 00:00Summary
The public /solution_id_{id}.html route calls Faq::getIdFromSolutionId() in phpmyfaq/src/phpMyFAQ/Faq.php:1312. That query joins faqdata with faqcategoryrelations solely by solution_id and returns the matching FAQ's id, lang, thema (title), and category_id with no permission filter. An unauthenticated visitor hits the route with a sequential integer and the server 301-redirects to /content/<category>/<id>/<lang>/<title-slug>.html, leaking the FAQ's existence, internal id, language, category binding, and title via the redirect's Location header and the redirected page's canonical link, share-to-social URLs, and hidden form fields. The related getFaqBySolutionId() at line 1221 contains an explicit fallback query (added "for tests") that also bypasses the permission filter, widening the blast radius to any callsite that trusts its result.
Details
The sink: getIdFromSolutionId() has no permission filter
phpmyfaq/src/phpMyFAQ/Faq.php:1312:
public function getIdFromSolutionId(int $solutionId): array
{
$query = sprintf(
'SELECT fd.id, fd.lang, fd.thema AS question, fd.content, fcr.category_id
FROM %sfaqdata fd
LEFT JOIN %sfaqcategoryrelations fcr
ON fd.id = fcr.record_id AND fd.lang = fcr.record_lang
WHERE fd.solution_id = %d',
Database::getTablePrefix(),
Database::getTablePrefix(),
$solutionId,
);
// ...
}
No WHERE-clause permission filter, no group/user filter. Every callsite that trusts this method exposes restricted FAQs. The route at phpmyfaq/src/phpMyFAQ/Controller/Frontend/FaqController.php:172 uses this result to compute a slugified URL and 301-redirects to it:
#[Route(path: '/solution_id_{solutionId}.html', name: 'public.faq.solution', methods: ['GET'])]
public function solution(Request $request): Response
{
$solutionId = Filter::filterVar($request->attributes->get('solutionId'), FILTER_VALIDATE_INT, 0);
// ...
$faqData = $this->faq->getIdFromSolutionId($solutionId);
if ($faqData === []) {
return new Response('', Response::HTTP_NOT_FOUND);
}
$slug = TitleSlugifier::slug($faqData['question']);
$url = sprintf('/content/%d/%d/%s/%s.html',
$faqData['category_id'], $faqData['id'], $faqData['lang'], $slug);
return new RedirectResponse($url, Response::HTTP_MOVED_PERMANENTLY);
}
The redirect URL embeds the title slug, so an unauthenticated visitor observes the title directly even though the canonical /content/<...>.html page may deny rendering the body.
Related sink: getFaqBySolutionId() explicitly falls back without the filter
phpmyfaq/src/phpMyFAQ/Faq.php:1256-1265:
if (false === $row || null === $row) {
// Fallback without permission filter to ensure retrieval in non-authenticated contexts (e.g., tests)
$fallbackQuery = sprintf(
'SELECT * FROM %sfaqdata fd WHERE fd.solution_id = %d LIMIT 1',
Database::getTablePrefix(),
$solutionId,
);
$fallbackResult = $this->configuration->getDb()->query($fallbackQuery);
$row = $this->configuration->getDb()->fetchObject($fallbackResult);
}
The inline comment confirms the fallback was introduced for test convenience. In production, the fallback fires exactly when the permission-filtered query returns zero rows (because the caller is unauthenticated or lacks group/user permission) and populates every field of faqRecord, including content, keywords, author, email, and notes. Downstream consumers that expect faqRecord to respect ACLs no longer do.
Entry enumeration
Solution IDs are monotonically increasing integers (faqdata.solution_id). An attacker enumerates /solution_id_<n>.html from 1 upward and records every non-404 response to discover the full set of FAQs on the instance, including ones restricted to admin-only groups or specific users.
Proof of Concept
Prerequisites: a phpMyFAQ instance has at least one FAQ record restricted to a specific user or group via faqdata_user / faqdata_group. Note its solution_id, which is assigned sequentially starting from a six-digit base.
Step 1. Anonymous GET of the solution URL:
curl -sS -L -o /tmp/out.html -w 'HTTP %{http_code}\n' \
'http://<host>/solution_id_<restricted-solution-id>.html'
Step 2. Observe the 301 redirect that getIdFromSolutionId() returns. The Location header carries the slugified title of the restricted FAQ directly in the URL path:
HTTP/1.1 301 Moved Permanently
Location: /content/<category-id>/<record-id>/<lang>/<title-slug>.html
Step 3. The redirected content page embeds the same metadata in client-controlled sinks, even when the body rendering is suppressed by a separate permission check:
<link rel="canonical" href="http://<host>/content/<category-id>/<record-id>/<lang>/<title-slug>.html">
<input type="hidden" name="voting-id" value="<record-id>">
<a href="http://<host>/pdf/<category-id>/<record-id>/<lang>">...</a>
Step 4. Enumerate solution IDs to discover every FAQ on the instance, including those the permission model intended to hide:
for id in $(seq 1 100000); do
code=$(curl -sS -o /dev/null -w '%{http_code}' "http://<host>/solution_id_${id}.html")
if [ "$code" = "301" ]; then
loc=$(curl -sSI "http://<host>/solution_id_${id}.html" | awk -F': ' '/^Location:/{print $2}' | tr -d '\r')
echo "solution_id=${id} -> ${loc}"
fi
done
Each 301 response's Location header reveals category, id, language, and title of a FAQ whose existence the permission model meant to hide.
Impact
Any unauthenticated visitor discovers the full set of FAQ entries on the instance, including the subset restricted to specific groups or users, and reads the title of every restricted FAQ. Deployments that use phpMyFAQ to host internal-only content alongside public content (staff knowledge bases, internal SOPs, confidential customer notes) lose the confidentiality of titles and of the fact that those FAQs exist. Slugified titles often encode the subject directly (for example q3-layoff-plan, aws-root-key-rotation), so the title alone can be sensitive.
The body content is usually still served through a separate permission-enforcing path on the canonical /content/<...>.html URL, so full-body disclosure requires the caller to also defeat that path (for example by combining with a session from any low-privilege account). The title-plus-existence leak is sufficient on its own to harm confidentiality in deployments where titles encode what the FAQ is about.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N (Medium, 5.3). CWE-863.
Recommended Fix
Add a permission filter to getIdFromSolutionId() the same way getFaqBySolutionId() builds one for its primary query (using QueryHelper::queryPermission()):
public function getIdFromSolutionId(int $solutionId): array
{
$queryHelper = new QueryHelper($this->user, $this->groups);
$query = sprintf(
'SELECT fd.id, fd.lang, fd.thema AS question, fd.content, fcr.category_id
FROM %sfaqdata fd
LEFT JOIN %sfaqcategoryrelations fcr
ON fd.id = fcr.record_id AND fd.lang = fcr.record_lang
LEFT JOIN (
SELECT record_id, group_id FROM %sfaqdata_group fdg WHERE fdg.group_id <> -1
UNION ALL
SELECT fd.id AS record_id, -1 AS group_id FROM %sfaqdata fd WHERE fd.solution_id = %d
) AS fdg ON fd.id = fdg.record_id
LEFT JOIN %sfaqdata_user fdu ON fd.id = fdu.record_id
WHERE fd.solution_id = %d %s',
Database::getTablePrefix(),
Database::getTablePrefix(),
Database::getTablePrefix(),
Database::getTablePrefix(),
$solutionId,
Database::getTablePrefix(),
$solutionId,
$queryHelper->queryPermission($this->groupSupport),
);
// ...
}
Separately, remove the unconditional fallback in getFaqBySolutionId() at Faq.php:1256-1265. If the permission-filtered query returns no rows, the FAQ is not visible to this caller; the method should leave faqRecord empty rather than re-query without the filter. If tests rely on the old behavior, replace the production fallback with a dedicated test helper or a flag that is disabled outside test bootstrap.
Found by aisafe.io
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.1"
},
"package": {
"ecosystem": "Packagist",
"name": "thorsten/phpmyfaq"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.1"
},
"package": {
"ecosystem": "Packagist",
"name": "phpmyfaq/phpmyfaq"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-46366"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-06T20:45:01Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nThe public `/solution_id_{id}.html` route calls `Faq::getIdFromSolutionId()` in `phpmyfaq/src/phpMyFAQ/Faq.php:1312`. That query joins `faqdata` with `faqcategoryrelations` solely by `solution_id` and returns the matching FAQ\u0027s `id`, `lang`, `thema` (title), and `category_id` with no permission filter. An unauthenticated visitor hits the route with a sequential integer and the server 301-redirects to `/content/\u003ccategory\u003e/\u003cid\u003e/\u003clang\u003e/\u003ctitle-slug\u003e.html`, leaking the FAQ\u0027s existence, internal id, language, category binding, and title via the redirect\u0027s `Location` header and the redirected page\u0027s canonical link, share-to-social URLs, and hidden form fields. The related `getFaqBySolutionId()` at line 1221 contains an explicit fallback query (added \"for tests\") that also bypasses the permission filter, widening the blast radius to any callsite that trusts its result.\n\n## Details\n\n### The sink: `getIdFromSolutionId()` has no permission filter\n\n`phpmyfaq/src/phpMyFAQ/Faq.php:1312`:\n\n```php\npublic function getIdFromSolutionId(int $solutionId): array\n{\n $query = sprintf(\n \u0027SELECT fd.id, fd.lang, fd.thema AS question, fd.content, fcr.category_id\n FROM %sfaqdata fd\n LEFT JOIN %sfaqcategoryrelations fcr\n ON fd.id = fcr.record_id AND fd.lang = fcr.record_lang\n WHERE fd.solution_id = %d\u0027,\n Database::getTablePrefix(),\n Database::getTablePrefix(),\n $solutionId,\n );\n // ...\n}\n```\n\nNo `WHERE`-clause permission filter, no group/user filter. Every callsite that trusts this method exposes restricted FAQs. The route at `phpmyfaq/src/phpMyFAQ/Controller/Frontend/FaqController.php:172` uses this result to compute a slugified URL and 301-redirects to it:\n\n```php\n#[Route(path: \u0027/solution_id_{solutionId}.html\u0027, name: \u0027public.faq.solution\u0027, methods: [\u0027GET\u0027])]\npublic function solution(Request $request): Response\n{\n $solutionId = Filter::filterVar($request-\u003eattributes-\u003eget(\u0027solutionId\u0027), FILTER_VALIDATE_INT, 0);\n // ...\n $faqData = $this-\u003efaq-\u003egetIdFromSolutionId($solutionId);\n if ($faqData === []) {\n return new Response(\u0027\u0027, Response::HTTP_NOT_FOUND);\n }\n $slug = TitleSlugifier::slug($faqData[\u0027question\u0027]);\n $url = sprintf(\u0027/content/%d/%d/%s/%s.html\u0027,\n $faqData[\u0027category_id\u0027], $faqData[\u0027id\u0027], $faqData[\u0027lang\u0027], $slug);\n return new RedirectResponse($url, Response::HTTP_MOVED_PERMANENTLY);\n}\n```\n\nThe redirect URL embeds the title slug, so an unauthenticated visitor observes the title directly even though the canonical `/content/\u003c...\u003e.html` page may deny rendering the body.\n\n### Related sink: `getFaqBySolutionId()` explicitly falls back without the filter\n\n`phpmyfaq/src/phpMyFAQ/Faq.php:1256-1265`:\n\n```php\nif (false === $row || null === $row) {\n // Fallback without permission filter to ensure retrieval in non-authenticated contexts (e.g., tests)\n $fallbackQuery = sprintf(\n \u0027SELECT * FROM %sfaqdata fd WHERE fd.solution_id = %d LIMIT 1\u0027,\n Database::getTablePrefix(),\n $solutionId,\n );\n $fallbackResult = $this-\u003econfiguration-\u003egetDb()-\u003equery($fallbackQuery);\n $row = $this-\u003econfiguration-\u003egetDb()-\u003efetchObject($fallbackResult);\n}\n```\n\nThe inline comment confirms the fallback was introduced for test convenience. In production, the fallback fires exactly when the permission-filtered query returns zero rows (because the caller is unauthenticated or lacks group/user permission) and populates every field of `faqRecord`, including `content`, `keywords`, `author`, `email`, and `notes`. Downstream consumers that expect `faqRecord` to respect ACLs no longer do.\n\n### Entry enumeration\n\nSolution IDs are monotonically increasing integers (`faqdata.solution_id`). An attacker enumerates `/solution_id_\u003cn\u003e.html` from 1 upward and records every non-404 response to discover the full set of FAQs on the instance, including ones restricted to admin-only groups or specific users.\n\n## Proof of Concept\n\nPrerequisites: a phpMyFAQ instance has at least one FAQ record restricted to a specific user or group via `faqdata_user` / `faqdata_group`. Note its `solution_id`, which is assigned sequentially starting from a six-digit base.\n\nStep 1. Anonymous GET of the solution URL:\n\n```bash\ncurl -sS -L -o /tmp/out.html -w \u0027HTTP %{http_code}\\n\u0027 \\\n \u0027http://\u003chost\u003e/solution_id_\u003crestricted-solution-id\u003e.html\u0027\n```\n\nStep 2. Observe the 301 redirect that `getIdFromSolutionId()` returns. The `Location` header carries the slugified title of the restricted FAQ directly in the URL path:\n\n```\nHTTP/1.1 301 Moved Permanently\nLocation: /content/\u003ccategory-id\u003e/\u003crecord-id\u003e/\u003clang\u003e/\u003ctitle-slug\u003e.html\n```\n\nStep 3. The redirected content page embeds the same metadata in client-controlled sinks, even when the body rendering is suppressed by a separate permission check:\n\n```html\n\u003clink rel=\"canonical\" href=\"http://\u003chost\u003e/content/\u003ccategory-id\u003e/\u003crecord-id\u003e/\u003clang\u003e/\u003ctitle-slug\u003e.html\"\u003e\n\u003cinput type=\"hidden\" name=\"voting-id\" value=\"\u003crecord-id\u003e\"\u003e\n\u003ca href=\"http://\u003chost\u003e/pdf/\u003ccategory-id\u003e/\u003crecord-id\u003e/\u003clang\u003e\"\u003e...\u003c/a\u003e\n```\n\nStep 4. Enumerate solution IDs to discover every FAQ on the instance, including those the permission model intended to hide:\n\n```bash\nfor id in $(seq 1 100000); do\n code=$(curl -sS -o /dev/null -w \u0027%{http_code}\u0027 \"http://\u003chost\u003e/solution_id_${id}.html\")\n if [ \"$code\" = \"301\" ]; then\n loc=$(curl -sSI \"http://\u003chost\u003e/solution_id_${id}.html\" | awk -F\u0027: \u0027 \u0027/^Location:/{print $2}\u0027 | tr -d \u0027\\r\u0027)\n echo \"solution_id=${id} -\u003e ${loc}\"\n fi\ndone\n```\n\nEach `301` response\u0027s `Location` header reveals category, id, language, and title of a FAQ whose existence the permission model meant to hide.\n\n## Impact\n\nAny unauthenticated visitor discovers the full set of FAQ entries on the instance, including the subset restricted to specific groups or users, and reads the title of every restricted FAQ. Deployments that use phpMyFAQ to host internal-only content alongside public content (staff knowledge bases, internal SOPs, confidential customer notes) lose the confidentiality of titles and of the fact that those FAQs exist. Slugified titles often encode the subject directly (for example `q3-layoff-plan`, `aws-root-key-rotation`), so the title alone can be sensitive.\n\nThe body content is usually still served through a separate permission-enforcing path on the canonical `/content/\u003c...\u003e.html` URL, so full-body disclosure requires the caller to also defeat that path (for example by combining with a session from any low-privilege account). The title-plus-existence leak is sufficient on its own to harm confidentiality in deployments where titles encode what the FAQ is about.\n\n`CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N` (Medium, 5.3). CWE-863.\n\n## Recommended Fix\n\nAdd a permission filter to `getIdFromSolutionId()` the same way `getFaqBySolutionId()` builds one for its primary query (using `QueryHelper::queryPermission()`):\n\n```php\npublic function getIdFromSolutionId(int $solutionId): array\n{\n $queryHelper = new QueryHelper($this-\u003euser, $this-\u003egroups);\n $query = sprintf(\n \u0027SELECT fd.id, fd.lang, fd.thema AS question, fd.content, fcr.category_id\n FROM %sfaqdata fd\n LEFT JOIN %sfaqcategoryrelations fcr\n ON fd.id = fcr.record_id AND fd.lang = fcr.record_lang\n LEFT JOIN (\n SELECT record_id, group_id FROM %sfaqdata_group fdg WHERE fdg.group_id \u003c\u003e -1\n UNION ALL\n SELECT fd.id AS record_id, -1 AS group_id FROM %sfaqdata fd WHERE fd.solution_id = %d\n ) AS fdg ON fd.id = fdg.record_id\n LEFT JOIN %sfaqdata_user fdu ON fd.id = fdu.record_id\n WHERE fd.solution_id = %d %s\u0027,\n Database::getTablePrefix(),\n Database::getTablePrefix(),\n Database::getTablePrefix(),\n Database::getTablePrefix(),\n $solutionId,\n Database::getTablePrefix(),\n $solutionId,\n $queryHelper-\u003equeryPermission($this-\u003egroupSupport),\n );\n // ...\n}\n```\n\nSeparately, remove the unconditional fallback in `getFaqBySolutionId()` at `Faq.php:1256-1265`. If the permission-filtered query returns no rows, the FAQ is not visible to this caller; the method should leave `faqRecord` empty rather than re-query without the filter. If tests rely on the old behavior, replace the production fallback with a dedicated test helper or a flag that is disabled outside test bootstrap.\n\n---\n*Found by [aisafe.io](https://aisafe.io)*",
"id": "GHSA-99qv-g4x9-mgc3",
"modified": "2026-06-09T00:00:00Z",
"published": "2026-05-06T20:45:01Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-99qv-g4x9-mgc3"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46366"
},
{
"type": "PACKAGE",
"url": "https://github.com/thorsten/phpMyFAQ"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/phpmyfaq-unauthenticated-information-disclosure-via-getidfromsolutionid-permission-bypass"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "phpMyFAQ has unauthenticated FAQ permission bypass via getFaqBySolutionId fallback query"
}
GHSA-99VM-5V2H-H6R6
Vulnerability from github – Published: 2025-02-19 17:46 – Updated: 2025-02-19 19:59Summary
If there are two overlapping policies for the update action that allow access to different fields, instead of correctly checking access permissions against the item they apply for the user is allowed to update the superset of fields allowed by any of the policies.
E.g. have one policy allowing update access to field_a if the id == 1 and one policy allowing update access to field_b if the id == 2. The user with both these policies is allowed to update both field_a and field_b for the items with ids 1 and 2.
Details
Before v11, if a user was allowed to update an item they were allowed to update the fields that the single permission, that applied to that item, listed. With overlapping permissions this isn't as clear cut anymore and the union of fields might not be the fields the user is allowed to update for that specific item.
The solution that this PR introduces is to evaluate the permissions for each field that the user tries to update in the validateItemAccess DB query, instead of only verifying access to the item as a whole. This is done by, instead of returning the actual field value, returning a flag that indicates if the user has access to that field. This uses the same case/when mechanism that is used for stripping out non permitted field that is at the core of the permissions engine.
As a result, for every item that the access is validated for, the expected result is an item that has either 1 or null for all the "requested" fields instead of any of the actual field values. These results are not useful for anything other than verifying the field level access permissions.
The final check in validateItemAccess can either fail if the number of items does not match the number of items the access is checked for (ie. the user does not have access to the item at all) or if not all of the passed in fields have access permissions for any of the returned items.
Impact
This is a vulnerability that allows update access to unintended fields, potentially impacting the password field for user accounts.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "directus"
},
"ranges": [
{
"events": [
{
"introduced": "11.0.0"
},
{
"fixed": "11.1.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@directus/api"
},
"ranges": [
{
"events": [
{
"introduced": "22.0.0"
},
{
"fixed": "23.1.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-27089"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2025-02-19T17:46:27Z",
"nvd_published_at": "2025-02-19T17:15:15Z",
"severity": "MODERATE"
},
"details": "### Summary\nIf there are two overlapping policies for the `update` action that allow access to different fields, instead of correctly checking access permissions against the item they apply for the user is allowed to update the superset of fields allowed by any of the policies. \n\nE.g. have one policy allowing update access to `field_a` if the `id == 1` and one policy allowing update access to `field_b` if the `id == 2`. The user with both these policies is allowed to update both `field_a` and `field_b` for the items with ids `1` and `2`. \n\n### Details\nBefore v11, if a user was allowed to update an item they were allowed to update the fields that the single permission, that applied to that item, listed. With overlapping permissions this isn\u0027t as clear cut anymore and the union of fields might not be the fields the user is allowed to update for that specific item.\n\nThe solution that this PR introduces is to evaluate the permissions for each field that the user tries to update in the validateItemAccess DB query, instead of only verifying access to the item as a whole. This is done by, instead of returning the actual field value, returning a flag that indicates if the user has access to that field. This uses the same case/when mechanism that is used for stripping out non permitted field that is at the core of the permissions engine.\n\nAs a result, for every item that the access is validated for, the expected result is an item that has either 1 or null for all the \"requested\" fields instead of any of the actual field values. These results are not useful for anything other than verifying the field level access permissions.\n\nThe final check in validateItemAccess can either fail if the number of items does not match the number of items the access is checked for (ie. the user does not have access to the item at all) or if not all of the passed in fields have access permissions for any of the returned items.\n\n### Impact\nThis is a vulnerability that allows update access to unintended fields, potentially impacting the password field for user accounts.",
"id": "GHSA-99vm-5v2h-h6r6",
"modified": "2025-02-19T19:59:54Z",
"published": "2025-02-19T17:46:27Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/directus/directus/security/advisories/GHSA-99vm-5v2h-h6r6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-27089"
},
{
"type": "WEB",
"url": "https://github.com/directus/directus/commit/a7ea67783b060d0d6fc964d71c2d4575d5eee4e2"
},
{
"type": "PACKAGE",
"url": "https://github.com/directus/directus"
},
{
"type": "WEB",
"url": "https://github.com/directus/directus/releases/tag/v11.1.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Directus allows updates to non-allowed fields due to overlapping policies"
}
GHSA-9C2C-P776-G29V
Vulnerability from github – Published: 2022-05-24 19:18 – Updated: 2022-07-13 00:01IBM Standards Processing Engine (IBM Transformation Extender Advanced 9.0 and 10.0) does not set the secure attribute on authorization tokens or session cookies. Attackers may be able to get the cookie values by sending a http:// link to a user or by planting this link in a site the user goes to. The cookie will be sent to the insecure link and the attacker can then obtain the cookie value by snooping the traffic. IBM X-Force ID: 207090.
{
"affected": [],
"aliases": [
"CVE-2021-29883"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-10-21T17:15:00Z",
"severity": "MODERATE"
},
"details": "IBM Standards Processing Engine (IBM Transformation Extender Advanced 9.0 and 10.0) does not set the secure attribute on authorization tokens or session cookies. Attackers may be able to get the cookie values by sending a http:// link to a user or by planting this link in a site the user goes to. The cookie will be sent to the insecure link and the attacker can then obtain the cookie value by snooping the traffic. IBM X-Force ID: 207090.",
"id": "GHSA-9c2c-p776-g29v",
"modified": "2022-07-13T00:01:18Z",
"published": "2022-05-24T19:18:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-29883"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/207090"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/6507077"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation
- Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries.
- Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
Mitigation
Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
Mitigation MIT-4.4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
Mitigation
- For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page.
- One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
Mitigation
Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
No CAPEC attack patterns related to this CWE.