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.
5641 vulnerabilities reference this CWE, most recent first.
GHSA-98MX-4VV7-3PQ6
Vulnerability from github – Published: 2023-01-31 12:30 – Updated: 2023-02-08 03:30Incorrect Authorization vulnerability in Apache Software Foundation Apache IoTDB.This issue affects the iotdb-web-workbench component from 0.13.0 before 0.13.3. iotdb-web-workbench is an optional component of IoTDB, providing a web console of the database. This problem is fixed from version 0.13.3 of iotdb-web-workbench onwards.
{
"affected": [],
"aliases": [
"CVE-2023-24829"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-01-31T10:15:00Z",
"severity": "HIGH"
},
"details": "Incorrect Authorization vulnerability in Apache Software Foundation Apache IoTDB.This issue affects the iotdb-web-workbench component from 0.13.0 before 0.13.3. iotdb-web-workbench is an optional component of IoTDB, providing a web console of the database. This problem is fixed from version 0.13.3 of iotdb-web-workbench onwards.",
"id": "GHSA-98mx-4vv7-3pq6",
"modified": "2023-02-08T03:30:25Z",
"published": "2023-01-31T12:30:23Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-24829"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/l0b59hh046tyn4gqot0bdrpg8gxlksmo"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-98PX-6486-J7QC
Vulnerability from github – Published: 2023-06-06 16:41 – Updated: 2024-09-30 20:34Impact
A discovered oEmbed or image URL can bypass the url_preview_url_blacklist setting potentially allowing server side request forgery or bypassing network policies. Impact is limited to IP addresses allowed by the url_preview_ip_range_blacklist setting (by default this only allows public IPs) and by the limited information returned to the client:
- For discovered oEmbed URLs, any non-JSON response or a JSON response which includes non-oEmbed information is discarded.
- For discovered image URLs, any non-image response is discarded.
Systems which have URL preview disabled (via the url_preview_enabled setting) or have not configured a url_preview_url_blacklist are not affected.
Because of the uncommon configuration required, the limited information a malicious user, and the amount of guesses/time the attack would need; the severity is rated as low.
Patches
The issue is fixed by #15601.
Workarounds
The default configuration of the url_preview_ip_range_blacklist should protect against requests being made to internal infrastructure, URL previews of public URLs is expected.
Alternately URL previews could be disabled using the url_preview_enabled setting.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "matrix-synapse"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.85.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-32683"
],
"database_specific": {
"cwe_ids": [
"CWE-863",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2023-06-06T16:41:34Z",
"nvd_published_at": "2023-06-06T19:15:11Z",
"severity": "MODERATE"
},
"details": "### Impact\nA discovered oEmbed or image URL can bypass the `url_preview_url_blacklist` setting potentially allowing server side request forgery or bypassing network policies. Impact is limited to IP addresses allowed by the `url_preview_ip_range_blacklist` setting (by default this only allows public IPs) and by the limited information returned to the client:\n\n* For discovered oEmbed URLs, any non-JSON response or a JSON response which includes non-oEmbed information is discarded.\n* For discovered image URLs, any non-image response is discarded.\n\nSystems which have URL preview disabled (via the `url_preview_enabled` setting) or have not configured a `url_preview_url_blacklist` are not affected.\n\nBecause of the uncommon configuration required, the limited information a malicious user, and the amount of guesses/time the attack would need; the severity is rated as low.\n\n### Patches\n\nThe issue is fixed by #15601.\n\n### Workarounds\n\nThe default configuration of the `url_preview_ip_range_blacklist` should protect against requests being made to internal infrastructure, URL previews of public URLs is expected.\n\nAlternately URL previews could be disabled using the `url_preview_enabled` setting.",
"id": "GHSA-98px-6486-j7qc",
"modified": "2024-09-30T20:34:41Z",
"published": "2023-06-06T16:41:34Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/matrix-org/synapse/security/advisories/GHSA-98px-6486-j7qc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-32683"
},
{
"type": "WEB",
"url": "https://github.com/matrix-org/synapse/pull/15601"
},
{
"type": "PACKAGE",
"url": "https://github.com/matrix-org/synapse"
},
{
"type": "WEB",
"url": "https://github.com/matrix-org/synapse/releases/tag/v1.85.0"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/matrix-synapse/PYSEC-2023-85.yaml"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/X6DH5A5YEB5LRIPP32OUW25FCGZFCZU2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Synapse has URL deny list bypass via oEmbed and image URLs when generating previews"
}
GHSA-98Q5-67C3-CPJC
Vulnerability from github – Published: 2022-11-02 12:00 – Updated: 2022-11-03 12:00A permissions issue existed. This issue was addressed with improved permission validation. This issue is fixed in macOS Ventura 13. A malicious application may be able to read sensitive location information.
{
"affected": [],
"aliases": [
"CVE-2022-42788"
],
"database_specific": {
"cwe_ids": [
"CWE-732",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-11-01T20:15:00Z",
"severity": "MODERATE"
},
"details": "A permissions issue existed. This issue was addressed with improved permission validation. This issue is fixed in macOS Ventura 13. A malicious application may be able to read sensitive location information.",
"id": "GHSA-98q5-67c3-cpjc",
"modified": "2022-11-03T12:00:32Z",
"published": "2022-11-02T12:00:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-42788"
},
{
"type": "WEB",
"url": "https://support.apple.com/en-us/HT213488"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/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"
}
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.