“Exposing patches before CVEs since 2025”
Tuesday, August 11, 2026
Aug 7, 2026, 10:57 AM — openclaw/openclaw
Commit: e910324f101c77529641a9a3a613dde20a76bd96
Author: Peter Steinberger
Gateway connection URLs can embed basic-auth credentials or token/API-key query parameters. Before this patch, several diagnostic surfaces (`openclaw status`, `status --all` text/JSON, and `logs` CLI error output) printed the raw connection URL verbatim, including embedded secrets, and probe failure text/thrown errors could also echo credential-bearing URLs. This exposes live credentials to terminal output, log files, or bug reports pasted by operators.
const targetText = params.remoteUrlMissing
? `fallback ${params.gatewayConnection.url}`
: params.gatewayConnection.url;
...
error: resolveProbeFailureMessage(result),
...
const details = buildGatewayConnectionDetails({ url: opts.url });
Run `openclaw status --all --json` (or `openclaw logs --url wss://user:[email protected]/ws?token=secret&key=api-key`) against a remote gateway configured with a URL like `wss://user:[email protected]/ws?token=secret&key=api-key&X-Amz-Signature=signed`. Before the patch, the tool's status/JSON output or logs error diagnostics would include the raw URL string containing `password`, `token=secret`, `key=api-key`, and the signature verbatim, leaking credentials to anyone viewing the terminal output, CI logs, or a pasted bug report.
Aug 6, 2026, 11:21 PM — openclaw/openclaw
Commit: d64f5b6a096088f1739ecd0e8c2f7182a0e90ce7
Author: Leon-SK668
The Google Chat API client read error response bodies from remote/proxy servers and included the raw text verbatim in surfaced error messages without redaction. If a malicious or misconfigured upstream/proxy server reflected the request's Authorization header (bearer token) back in the error response body, that token would be exposed in error messages returned to users, logs, or downstream consumers. The fix applies forced redaction (redactToolPayloadText) to the error response text before it is used in any error message.
async function readGoogleChatErrorResponse(response: Response, label: string): Promise<string> {
return (
(await readResponseTextSnippet(response, {...})) ?? ""
);
}
A malicious/compromised proxy or upstream server responds to a Google Chat API request with a 403 status and body: {"error":{"message":"Chat permission denied"},"reflectedHeader":"Authorization: Bearer <secret-token>"}. Before the patch, deleteGoogleChatMessage (and other API calls) would throw an Error whose message contains the full string 'Authorization: Bearer <secret-token>', exposing the real bearer token to anyone viewing the error (logs, UI, agent output). After the patch, redactToolPayloadText strips the token before it reaches the error message.
Aug 6, 2026, 11:14 PM — grafana/grafana
Commit: e88041c9aee3ae2923327884b9c04be0325fe223
Author: Collin Fingar
The dashboard snapshot apiserver resolved snapshots by a global key without verifying that the snapshot belonged to the caller's organization/namespace. An authenticated user with snapshot delete permission in their own org could supply another org's public snapshot key to the `deletekey` subresource or `DELETE` endpoint, allowing them to read the secret deleteKey or delete a snapshot belonging to a different organization without proper authorization.
snap, err := s.Service.GetDashboardSnapshot(ctx, &dashboardsnapshots.GetDashboardSnapshotQuery{Key: name})
if err != nil || snap == nil {
return nil, false, err
}
// no org/namespace check before delete or before returning deleteKey
As a user authenticated in org 2 with snapshot delete RBAC permission, call GET /apis/dashboard.grafana.app/v0alpha1/namespaces/org-2/snapshots/<org-1-snapshot-key>/deletekey using the public snapshot key of a snapshot belonging to org 1. Before the patch, this returns the secret deleteKey for the org-1 snapshot; the caller can then issue DELETE /apis/dashboard.grafana.app/v0alpha1/namespaces/org-2/snapshots/<org-1-snapshot-key> to delete the org-1 snapshot, despite having no legitimate access to org 1's resources.
Aug 6, 2026, 02:26 PM — keycloak/keycloak
Patch landed 22 hours 53 minutes after CVE published
Commit: a569ef539a9d73e8b53634d6f368254a7052e2a8
Author: Alexander Schwartz
The Micrometer user event metrics listener created a distinct time-series counter for each unique combination of tags, including the 'error' tag (and clientId tag) which is derived from user-controllable input such as arbitrary exception messages or client IDs. An attacker could trigger many different error messages or use many distinct client IDs to generate an unbounded number of unique metric tag values, leading to unbounded memory growth in the metrics registry and potential OOM in Keycloak or downstream observability systems. The patch mitigates this by generifying error codes (e.g., using Errors.GENERIC/INVALID_SCOPE/CLIENT_NOT_FOUND instead of raw exception messages) and adding a MeterFilter that caps the number of distinct tag values (default 10000) for the error and clientId tags, denying new tag values once the limit is reached.
event.error(e.getMessage());
...
String msg = String.format("No client with clientId: %s found.", clientId);
event.error(msg);
...
String msg = String.format("Scope id %s does not exist for client %s.", scopeRepresentation, consent.getClient().getName());
event.error(msg);
An attacker repeatedly calls the account REST API endpoint (e.g., DELETE /realms/{realm}/account/applications/{clientId}/consent) with thousands of distinct, attacker-controlled clientId values such as clientId1, clientId2, ..., clientidN. Each request triggers event.error(msg) with a unique error message string like 'No client with clientId: clientId12345 found.', which becomes a unique 'error' tag value in the keycloak.user Micrometer counter, causing the metrics registry to accumulate unbounded unique time series and eventually exhaust JVM memory.
Aug 6, 2026, 09:44 AM — openclaw/openclaw
Commit: 818190bd26d82586e37b0e8efc8bfe9b809acda9
Author: Pavan Kumar Gondhi
The plugin-node capability authorizer only checked whether a capability token existed and was unexpired, without checking if the owning client had already been invalidated (e.g., removed by an operator). This allowed a removed node's already-issued capability URL to continue authorizing Canvas HTTP requests during the window between invalidation and full connection teardown, since the invalidated client remained in the clients set and its capability entry was still matched.
for (const client of params.clients) {
const entry = client.pluginNodeCapabilities?.[storageKey];
if (!entry || !isFutureDateTimestampMs(entry.expiresAtMs, { nowMs })) {
continue;
}
1. Node connects and receives a Canvas capability URL, e.g. http://gateway/__openclaw__/cap/<token>/__openclaw__/canvas/file.txt. 2. Operator removes the node, setting client.invalidated = true, but the WS connection close is still pending (client remains in the clients Set). 3. Before the patch, an attacker (or the still-connected node) sends GET http://gateway/__openclaw__/cap/<token>/__openclaw__/canvas/file.txt and receives 200 with the Canvas content, because hasAuthorizedPluginNodeCapability only checks expiresAtMs and ignores client.invalidated. 4. After the patch, the same request returns 401 immediately because invalidated clients are skipped in the authorization loop.
Aug 6, 2026, 09:08 AM — openclaw/openclaw
Commit: 528c5e08175fda0606590c8795330349bddc6858
Author: Pavan Kumar Gondhi
Feishu's message-action contract did not declare its native camel-case/snake-case chat identifier fields (chatId, chat_id, channel_id) as delivery targets for the edit, pin, and unpin actions. Because the shared cross-context policy engine only inspects declared delivery-target aliases, operators using these native Feishu fields could bypass the configured 'disable within-provider cross-context messaging' restriction and perform message mutations against a chat/conversation different from the current context.
export const messageActionTargetAliases = {
read: { aliases: ["messageId"] },
pin: { aliases: ["messageId"] },
unpin: { aliases: ["messageId"] },
...
};
With config tools.message.crossContext.allowWithinProvider=false and toolContext.currentChannelId='oc_current', call runMessageAction with action='pin' (or 'unpin'/'edit') and params={ channel: 'actionhub', messageId: 'om_pin', chatId: 'oc_foreign' }. Before the patch, because 'chatId' was not declared as a deliveryTargetAlias for pin/unpin, the cross-context guard never inspected it, so the pin action against a foreign chat 'oc_foreign' (different from the current conversation) would succeed instead of being rejected with 'Cross-context messaging denied'.
Aug 6, 2026, 08:41 AM — django/django
Commit: 89e82866dc2746383c336c7b10e050b9da3ae1ef
Author: Jakob Friedrich
When using Django admin's 'save as new' functionality, inline formsets for related models where the user lacks add permission (but has view permission) could be rendered as editable/populated forms upon a validation error re-render, because the total/initial form counts were not cleared before instantiating the formset. This allowed a user without add permission on the inline model to potentially submit and persist changes to inline objects that they should only be able to view, effectively bypassing the permission check enforced elsewhere in the admin.
formset_params = self.get_formset_kwargs(request, obj, inline, prefix) formset = FormSet(**formset_params)
A user with view-only permission on an inline model (e.g., Article under Section) but without add permission triggers a save-as-new POST that fails parent validation (e.g., submitting empty 'name' field) while including inline formset management data such as 'article_set-TOTAL_FORMS=1' and 'article_set-INITIAL_FORMS=1'. Because the code did not zero out these counts based on the add-permission check, the re-rendered formset shows editable inline forms with existing data, allowing an attacker to craft further POST requests that modify or add inline objects despite lacking add permission on that inline.
Aug 6, 2026, 03:38 AM — openclaw/openclaw
Commit: ab74723229b98b9df04f1d7b45f03e58d7ef5846
Author: Alix-007
When a proxy or upstream server reflected the Discord bot's Authorization header value back in an error response (either HTML/text or JSON body), the raw bot token would be included unredacted in the error message surfaced to users/logs. This could expose the bot credential to anyone who could view logs, error output, or troubleshooting UI. The patch adds redaction of the token via redactToolPayloadText before formatting the final error text and before summarizing HTML bodies.
function formatDiscordApiErrorText(text: string, response: Response): string | undefined {
const trimmed = text.trim();
...
return retryAfter ? `${message} (retry after ${retryAfter})` : message;
}
Set up a malicious/misconfigured proxy that echoes the Authorization header back in its error response, e.g. respond with body: `<html><body>proxy failure Authorization: Bot proof-prefix-discord-loopback-secret-proof-suffix; request rejected</body></html>` on a 502. Before the patch, calling requestDiscord('/gateway/bot', token, ...) would produce an error message containing the full bot token string in plaintext (visible in logs/console), e.g. 'Discord API /gateway/bot failed (502): proxy failure Authorization: Bot proof-prefix-discord-loopback-secret-proof-suffix; request rejected'. After the patch, the token is redacted so the leaked secret does not appear in the error text.
Aug 5, 2026, 08:20 PM — langchain-ai/langchain
Commit: 3e871a148d7bb6f542f4c2328523a57b8dff0afe
Author: John Kennedy
The evaluation runner copied the Git remote URL verbatim into LangSmith run tags without stripping embedded credentials (userinfo) from HTTPS or SSH-style URLs. If a developer's local git remote contained an access token or password (e.g., `https://user:[email protected]/...`), that secret would be persisted and exposed in run metadata/tags, which may be visible to other users or logged systems. The patch adds sanitization that strips userinfo while preserving host/path identity, and fails closed (omitting the tag) for ambiguous or malformed URLs.
for k, v in (project.metadata.get("git") or {}).items():
tags.append(f"git:{k}={v}")
If a developer's git remote is configured as `https://alice:[email protected]/org/private-repo.git`, running `run_on_dataset(...)` would previously produce a run tag: `git:remote_url=https://alice:[email protected]/org/private-repo.git`, leaking the GitHub personal access token into LangSmith run tags visible to anyone with access to that evaluation run/project.
Aug 5, 2026, 11:25 AM — grafana/grafana
Commit: 3e9bc31edb6b1346845c82b11f7494d08b7b7b7a
Author: Ezequiel Victorero
The ShortURL API authorizer allowed any authenticated user (including org role None) to update or patch the status subresource of any short URL object, regardless of ownership. This let non-privileged users, or even users with the lowest permission level, tamper with the status (e.g., lastSeenAt) field of short URLs belonging to other users/organizations, which the fix now restricts to admin-only access.
case "update", "patch":
if attr.GetSubresource() == "status" {
return authorizer.DecisionAllow, "", nil
}
As an authenticated user with OrgRole=None, send:
PATCH /apis/shorturl.grafana.app/v0alpha1/namespaces/{ns}/shorturls/{other-users-shorturl}/status
Body: {"status":{"lastSeenAt":"2099-01-01T00:00:00Z"}}
Before the patch this request is allowed by the authorizer for any authenticated user, letting a low-privileged user overwrite the status subresource of a short URL they do not own.
Aug 5, 2026, 09:41 AM — hashicorp/vault
Commit: 04f9af145954fd0dd532267c9694a7ba1fbb0c06
Author: Vault Automation
The DisplayName field, which is user/token controlled (e.g., from token display names or OIDC/JWT claims), was passed unsanitized into database username templates used to generate credentials, allowing SQL metacharacters or malicious payloads to be injected into generated usernames sent to the database. The patch adds sanitizeDisplayName to strip all characters except alphanumerics, hyphens, and underscores before using DisplayName in the credential generation request, and adds a warning for username_template usage without truncation.
newUserReq := v5.NewUserRequest{
UsernameConfig: v5.UsernameMetadata{
DisplayName: req.DisplayName,
RoleName: name,
},
Create a Vault token with a display name containing SQL injection payload, e.g. `x'; DROP TABLE users; --`, then request database credentials via `vault read database/creds/my-role`. The unsanitized DisplayName is substituted into the username_template (e.g. `{{.DisplayName}}_{{random 8}}`) and passed to the DB plugin's CREATE USER statement, potentially breaking out of the intended SQL context and executing injected SQL against the backend database.
Aug 5, 2026, 03:29 AM — openclaw/openclaw
Commit: 3bda007ca456ef2803c2a81fef24ba61c438a690
Author: Yuval Dinodia
The stdout data handler for MCP stdio child processes called ReadBuffer.append synchronously without a try/catch. When a server (or attacker-influenced tool-result payload) produces a stdout frame exceeding the 10MiB ReadBuffer cap, append() throws synchronously inside the event callback, resulting in an unhandled exception that crashes the entire host process and terminates all concurrent sessions. The patch wraps the append/processReadBuffer calls in a try/catch that routes errors to onerror and gracefully closes the transport instead of crashing.
child.stdout?.on("data", (chunk: Buffer) => {
this.readBuffer.append(chunk);
this.processReadBuffer();
})
A malicious or compromised MCP stdio server (or one relaying attacker-controlled tool-result data, e.g., a large fetched web page or file content) writes more than 10,485,760 bytes to stdout before a newline delimiter. For example: `process.stdout.write(Buffer.alloc(10*1024*1024+1, 'A'))` from the child MCP server process. This causes `ReadBuffer.append` to throw 'ReadBuffer exceeded maximum size of 10485760 bytes' synchronously inside the 'data' event handler, which Node treats as an uncaughtException, crashing the entire OpenClaw host process and killing all concurrent user sessions.
Aug 5, 2026, 02:25 AM — apache/airflow
Commit: 3a08a3d7792335ac9456cd44c92d8de3ae0d6ec1
Author: Jarek Potiuk
The BaseSerialization.deserialize method used import_string() on an attacker-controlled class name embedded in serialized DAG blobs (AIRFLOW_EXC_SER/BASE_EXC_SER nodes) to reconstruct exception objects. Because import_string will import arbitrary modules and access arbitrary attributes by dotted name, a crafted serialized DAG could cause the deserializer to import and execute code from any importable module (including modules with import-time side effects, or builtins like eval/os.system), leading to code execution or unintended behavior when a malicious/tampered serialized DAG is loaded. The patch restricts resolution to already-loaded classes validated as AirflowException subclasses or a fixed builtin allow-list, preventing import of attacker-named modules/classes.
if type_ == DAT.AIRFLOW_EXC_SER:
exc_cls = import_string(exc_cls_name)
else:
exc_cls = import_string(f"builtins.{exc_cls_name}")
Craft a serialized DAG object with a BASE_EXC_SER/AIRFLOW_EXC_SER node whose exc_cls_name is set to 'subprocess.check_output' or 'os.system' (or any module path with import-time side effects), e.g.:
encoded = BaseSerialization._encode(BaseSerialization.serialize({'exc_cls_name': 'os.system', 'args': ['id'], 'kwargs': {}}), type_=DagAttributeTypes.AIRFLOW_EXC_SER)
BaseSerialization.deserialize(encoded)
Before the patch, import_string('os.system') would import the os module and return system, which is then called as exc_cls(*args, **kwargs) i.e. os.system('id'), executing an arbitrary shell command when the malicious serialized DAG is deserialized.
Aug 4, 2026, 07:31 PM — grafana/grafana
Commit: 2b64f5c1f9febba82cedb964431f404bc870abab
Author: Ezequiel Victorero
The previous authorizer for the ShortURL Kubernetes API allowed any authenticated user, regardless of org role, to perform any operation including list, watch, delete, deletecollection, and update on any short URL resource. This means a low-privileged user (e.g., org role None or Viewer) could list all short URLs in the org (exposing internal paths/links created by other users) or delete/modify short URLs belonging to other users, since there was no ownership or role check.
if !attr.IsResourceRequest() {
return authorizer.DecisionNoOpinion, "", nil
}
// Any authenticated user can access the API
return authorizer.DecisionAllow, "", nil
As a low-privileged authenticated user (org role Viewer or None), send: DELETE /apis/shorturl.grafana.app/v1beta1/namespaces/{ns}/shorturls/{uid-of-another-users-shorturl} or GET /apis/shorturl.grafana.app/v1beta1/namespaces/{ns}/shorturls (list) — both succeed pre-patch, allowing the low-privileged user to enumerate or delete short URLs created by other users despite lacking admin/editor rights.
Aug 4, 2026, 05:48 PM — argoproj/argo-cd
Commit: 994e271bcc3c591540bbe778bf09df303dcbf5f7
Author: Peter Jiang
When performing a server-side diff on a Kubernetes Secret, the kubectl.kubernetes.io/last-applied-configuration annotation on the predicted-live (target) resource was not masked, even though the corresponding annotation on the live resource was hidden. Since this annotation can contain the full JSON representation of the applied Secret (including plaintext data values), it could leak secret contents in the diff output (e.g., displayed in Argo CD UI/CLI diffs or logs) even though HideSecretData was meant to redact secret values symmetrically.
if live != nil && liveLastAppliedAnnotation != nil {
... mask live's last-applied-configuration ...
}
// target's last-applied-configuration annotation was never masked
Create a Secret with data: {password: 'supersecret'} and annotate it (or have it annotated by kubectl apply) with kubectl.kubernetes.io/last-applied-configuration containing the full secret JSON with data.password base64-encoded plaintext. Run Argo CD's server-side diff (serverSideDiff) between the desired config and live state where the predicted-live object retains this annotation. Before the patch, the resulting PredictedLive diff output would include the un-redacted last-applied-configuration annotation, exposing the base64 'supersecret' value to anyone viewing the diff (e.g., via `argocd app diff` or the UI), even though the same value in .data.password was masked with '++++++++'.
Aug 4, 2026, 03:01 PM — openclaw/openclaw
Commit: d06fc25a0c580bb1854fd890e0d849270fbec487
Author: Vincent Koc
Shared group and channel chat sessions automatically loaded the workspace-root MEMORY.md file into the bootstrap context, exposing private long-term memory/context intended only for the main private session to all participants in a shared group or channel. Additionally, hooks could re-add or relabel the MEMORY.md file after initial filtering, bypassing session-type-based restrictions on private memory exposure. The patch enforces filtering of private memory files based on an authoritative chatType, re-applies the filter after hook mutations, and tracks file source identity to prevent relabeling/aliasing bypasses.
// Before: MEMORY.md loaded unconditionally at bootstrap regardless of chat type // resolveBootstrapFilesForRun did not accept/enforce chatType, // and hooks executed after initial filtering could re-add root MEMORY.md // or alias/relabel it to bypass any filtering that did occur.
In a shared Slack/Discord channel session (sessionKey like 'agent:main:slack:channel:c1'), the bootstrap resolver would load and inject the workspace-root MEMORY.md (containing private long-term memory) into the shared session context, exposing it to all members of the channel. E.g., a hook registered via agent:bootstrap could add {name: 'SOUL.md', path: workspaceDir/MEMORY.md} — relabeling MEMORY.md as SOUL.md — to bypass name-based filtering and leak private memory content into a group chat that any participant could read.
Aug 4, 2026, 02:53 PM — keycloak/keycloak
Commit: bce3153aa26207c07ac936112f4f30364eac4176
Author: Stefan Guilhen
The PatchRequest.setSchemas() method did not handle a null value for the 'schemas' field, allowing an unauthenticated or authenticated attacker to send a SCIM PATCH request with "schemas": null to trigger a NullPointerException on the server, resulting in an unhandled 500 error instead of a proper validation error (400). This could be used for minor denial-of-service or availability disruption of the SCIM PATCH endpoint.
public void setSchemas(Set<String> schemas) {
this.schemas = schemas;
}
PATCH /realms/{realm}/scim/v2/Users/{id} HTTP/1.1
Content-Type: application/scim+json
Authorization: Bearer <token>
{"schemas": null, "Operations": [{"op": "replace", "path": "active", "value": false}]}
Before the patch, this request triggers a NullPointerException on the server (uncaught exception / 500 error) because the schemas field is set to null and later dereferenced. After the patch, the server returns a proper 400 Bad Request.
Aug 4, 2026, 01:29 PM — openclaw/openclaw
Commit: 00f3fb24693dd9f813344b5d580cf857339bf300
Author: Vincent Koc
The DiscordRealtimeVoiceSession queued completed 'exact speech' messages without any bound on count or size while provider readiness, an active response, or playback prevented delivery. A stalled or misbehaving session could accumulate an unbounded backlog of speech text in memory, leading to unbounded memory growth and eventual resource exhaustion, and could later flush a large stale backlog. The patch introduces a fixed budget (32 messages / 32 KiB) and terminates the session on overflow, clearing state to prevent unbounded growth.
if (!this.bridgeReady || this.exactSpeechResponseActive || this.hasInterruptibleOutputAudio()) {
this.queuedExactSpeechMessages.push(text);
logger.info(
An attacker (or a stalled realtime provider) keeps a Discord voice session in a state where bridgeReady is false or exactSpeechResponseActive stays true indefinitely (e.g., by repeatedly triggering speech events while the provider never sends readiness/response-complete signals). Each incoming transcribed utterance calls the internal handler that unconditionally does `this.queuedExactSpeechMessages.push(text)` with no size/count cap. By continuously speaking or replaying audio into the channel for an extended period, the queue grows without bound (megabytes of text), consuming server memory indefinitely until the process OOMs or the stale backlog is dumped all at once when the session recovers.
Aug 4, 2026, 01:19 PM — apache/airflow
Commit: d41ac7b6d213682db3ef4d21bbb33e013dde4af4
Author: Jarek Potiuk
Configuration options registered as sensitive (like database connection strings with passwords) were only masked when queried under their base section name. Team-scoped overrides stored in `\[<team>=<section>\]` config sections or `AIRFLOW__<TEAM>___<SECTION>__<KEY>` environment variables bypassed the sensitivity check entirely, exposing secrets like database credentials in clear text via the config API and `as_dict()` output.
if (section_l, option_l) in conf.sensitive_config_values or _is_per_key_sensitive_option(
section_l, option_l
):
value = "< hidden >"
else:
value = conf.get(section, option)
Configure a team-scoped database override: set config section `[team_a=database]` with `sql_alchemy_conn = postgresql://user:secretpass@host/db`. Then query `GET /config/section/team_a=database/option/sql_alchemy_conn` via the Airflow API. Before the patch, the response returns the plaintext connection string with embedded password instead of `< hidden >`, because `(section_l, option_l)` = `("team_a=database", "sql_alchemy_conn")` never matches the base sensitive pair `("database", "sql_alchemy_conn")`.
Aug 4, 2026, 11:49 AM — django/django
📈 Patch landed 6 hours 41 minutes before CVE published
Commit: f1949c1f9758947ade984c895ff16bef46f56520
Author: Jacob Walls
GeoDjango spatial lookups optimistically parsed lookup values as GDALRaster before falling back to GEOSGeometry parsing. Because GDALRaster's constructor could interact with GDAL virtual filesystem drivers regardless of the write=False flag, a malicious string or dict passed into a spatial lookup (e.g., via the Django admin's changelist filtering, which allows staff users to submit arbitrary lookups) could cause the server to write files to disk or issue network requests to attacker-controlled URLs. The patch blocks strings and dicts from being treated as raster input in lookup contexts unless explicitly wrapped in GDALRaster, closing the SSRF/file-write vector while preserving normal model field assignment behavior.
def get_raster_prep_value(self, value, is_candidate):
if isinstance(value, gdal.GDALRaster):
return value
elif is_candidate:
try:
return gdal.GDALRaster(value)
except GDALException:
pass
As a staff user with view permission on a model containing a RasterField/GeometryField, submit an admin changelist filter such as:
GET /admin/app/model/?field__contains={"driver":"HTTP","source":"http://attacker.example/malicious.tif"}
or a raw string path like:
GET /admin/app/model/?field__contains=/vsicurl/http://attacker.example/payload.tif
Before the patch, this dict/string would be passed to `gdal.GDALRaster(value)` during `get_prep_value`, causing GDAL to attempt to open/write the referenced raster (e.g., fetching from the attacker's server or writing a file to disk via certain drivers), even though the constructor requested write=False. After the patch, such strings/dicts are rejected with `DisallowedRasterLookup` unless explicitly wrapped by the caller in `GDALRaster(...)`.
Aug 4, 2026, 11:49 AM — django/django
📈 Patch landed 6 hours 41 minutes before CVE published
Commit: 27137e655e442e81095f1f8f77ff3870d9fdf169
Author: Natalia
The check_for_language() function used an lru_cache with maxsize=1000, but did not limit the length of the lang_code strings used as cache keys. An attacker could submit many distinct, very long language codes (e.g., via the set_language() view's POST data), causing up to 1000 large strings to be retained in memory as cache keys, consuming excessive process memory. The patch adds a length check (max 500 characters) before the cached lookup, so long codes are rejected without being cached.
@functools.lru_cache(maxsize=1000)
def check_for_language(lang_code):
if lang_code is None or not language_code_re.search(lang_code):
return False
return any(...)
POST to django.views.i18n.set_language with 1000 distinct 'language' values each ~100KB long (e.g., 'a'*100000 + str(i) for i in range(1000)). Each unique value becomes a cache key in check_for_language's lru_cache, retaining ~100MB of string data in memory per worker process, potentially exhausting memory across multiple requests/workers.
Aug 4, 2026, 11:49 AM — django/django
📈 Patch landed 6 hours 41 minutes before CVE published
Commit: d2e59b77fe18de318a8272c2a7bbc798d84d1d0d
Author: Jacob Walls
Before this patch, GEOSGeometry parsing (from WKT or WKB) had no limit on the depth or number of nested GEOMETRYCOLLECTION elements. Because GEOS parses these recursively, a maliciously crafted input with deeply nested geometry collections could exhaust the stack or memory and trigger a fatal error/crash in GEOS, effectively causing a denial of service in any application that accepts user-supplied geometry data (e.g., via GeometryField model/form fields). The patch introduces a `max_geom_collections` parameter, forwarded through GEOSGeometry, model fields, and form fields, to cap the depth (for WKT) or total count (for WKB) of nested collections before they reach the GEOS library.
def __init__(self, geo_input, srid=None):
...
g = self._from_wkt(force_bytes(wkt_m["wkt"]))
...
g = wkb_r().read(force_bytes(wkb_input))
Submit a WKT string with thousands of nested GEOMETRYCOLLECTION wrappers to a Django application using a GeometryField, e.g.:
value = 'GEOMETRYCOLLECTION(' * 100000 + 'POINT(0 0)' + ')' * 100000
GEOSGeometry(value)
Prior to the patch, this unbounded recursive parsing could cause GEOS to crash with a stack overflow or fatal error, taking down the worker process handling the request (DoS). After the patch, GEOSGeometry(value, max_geom_collections=N) rejects such deeply nested input before it reaches GEOS, raising a ValueError instead of crashing.
Aug 4, 2026, 11:49 AM — django/django
📈 Patch landed 6 hours 41 minutes before CVE published
Commit: 47511a21026cdd721d8fbf8571cc079bc38bb46d
Author: Natalia
The Django admin's display_for_field() rendered URLField values as clickable <a href> links without validating the URL scheme. A stored value using a dangerous scheme like javascript: or data: would be rendered as a clickable link, and clicking it would execute arbitrary script in the authenticated admin session (staff user context).
elif isinstance(field, models.URLField) and value and not avoid_link:
return format_html('<a href="{}">{}</a>', value, value)
Store a URLField value of `javascript:alert(document.cookie)` (or `data:text/html,<script>alert(1)</script>`) in a model instance via a form that doesn't enforce standard URL validation (e.g., a custom form field, bulk import, or a field without full URLValidator applied at save time). When a staff user views the changelist or read-only change form for that object, the admin renders `<a href="javascript:alert(document.cookie)">javascript:alert(document.cookie)</a>`. Clicking that link executes the JavaScript in the authenticated admin session, allowing session hijacking or arbitrary actions as that staff user.
Jul 26, 2026, 01:43 AM — nodejs/node
Commit: d4d35c6363af31a52764d1fb63e8a99734226997
Author: Mohamed Sayed
The Session object held only a weak reference (BaseObjectWeakPtr) to its parent DatabaseSync. If the JavaScript DatabaseSync object was garbage collected (and its underlying sqlite3 database closed/freed) while a Session created from it was still alive, subsequent operations on the session (e.g., changeset()) would dereference the freed database pointer, causing a use-after-free and crash (SIGSEGV). The fix changes the reference to a strong BaseObjectPtr so the database is kept alive as long as the session exists.
BaseObjectPtr<Session> session =
Session::Create(env, BaseObjectWeakPtr<DatabaseSync>(db), pSession);
...
BaseObjectWeakPtr<DatabaseSync> database_; // The Parent Database
const { DatabaseSync } = require('node:sqlite');
let session = (() => {
const database = new DatabaseSync(':memory:');
database.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)');
const s = database.createSession();
database.exec("INSERT INTO data VALUES (1, 'hello')");
return s; // database reference dropped here, only session remains
})();
global.gc(); // with --expose-gc, forces collection of the now-unreferenced DatabaseSync
session.changeset(); // dereferences freed sqlite3* -> SIGSEGV crash (before patch)
Jul 25, 2026, 02:40 PM — nodejs/node
Commit: 3e06d536a9c3425bc8691ad7bb30918b45e4ae75
Author: RajeshKumar11
StringBytes::StorageSize contained a CHECK that fatally aborted the process when a hex-encoded string of odd length was written via Writev (e.g. an HTTP request body written before it is corked/flushed). This allowed a remote or local attacker who can influence data written as 'hex' encoding through a batched write path to crash the Node.js process, resulting in a denial of service. The patch removes the CHECK and uses integer division, consistent with the non-crashing single-write path.
case HEX: CHECK(view.length() % 2 == 0 && "invalid hex string length"); data_size = view.length() / 2; break;
const http = require('http');
const req = http.request('http://example.org', { method: 'POST' });
req.write('1', 'hex'); // odd-length hex string triggers CHECK failure and crashes the process due to auto-corking in http.request